面向对象的特征(封装、继承、多态、抽象)

面向对象(思想)

权限修饰:

  • public: 公开的,所有不同的包,不同的类全都可以访问得到。
  • private: 私有的,只有自己的类(同一个class)中可以访问,其他的都访问不到。
  • protected: 受保护的,除了不同包的其他类访问不到,其他都可以访问到,不同包的子类也可以 访问的到。
  • 默认:只有同一个包中的类可以访问到,不同包访问不到。

封装:

  • 实际含义是:该隐藏的隐藏,该暴露的暴露

  • 全局变量:定义在类中的,所有方法都可以访问到,叫全局变量

  • 局部变量:定义在一个方法里的,只有本方法可以访问的叫局部变量

定义变量:

? 权限修饰符(public) + 类型(void、int、string、array[]...) + 变量名称

注:变量名称要用合法的JAVA标识符,首单词的第一个字母小写,后面的每一个单词首字母大写

可变参数:
public static void test(int...a){
	for(int i=0;i<a.length;i++){
		System.out.println(a[i]);
	}
}
  • 当不确定参数内要传多少个时,用int... 在调用test方法时,可以任意传几个参数,同时会把a当作数组进行处理

  • 注:

    • 如果一个参数里有可变参数,并且有多个参数,那么可变参数一定要放在最后一个

    • public static void test(int b,int...a){
      	for(int i=0;i<a.length;i++){
      		System.out.println(a[i]);
      	}
      }
      
方法封装:
  • -定义格式: 修饰符(private) + 返回值类型(void、int、string....) + 方法名(自定义)+

( 参数类型 参数名称 + , + 参数类型 参数名称) + { 代码体 + return 表达式 }

  • 形式参数:在参数名称中,方法本身起的名字叫形式参数,只起一个代号的作用。

  • 实际参数:在通过 . 调用方法时,依据形式参数传进的东西是实际参数。

  • 不需要new对象就可以访问的方法封装:

    ? public static Person getPerson(){

    ? return new Person();

    ? }

  • 方法封装的好处:1.方便维护 2.减少冗余代码的出现

构造方法:
  • 作用:用于该类的实例对象的初始化

  • 格式: public Person(){ }

  • 示例: pubilc int size;

    ? pubilec Person(){

    ? size=18;

    ? }

    • 这就是给对象做了初始化,只要在另一个类中调用了Person的方法,new出了Person,那么当输出size时,默认输出18.
    • 构造方法中也可以传参数,当传入了参数后,再调用此方法是就必须传进参数对应的类型,如果想既可以传参数,也可以不传参数,那么就再构造一个同名的方法,该方法不加任何参数,这就叫构造方法的重载
This关键字
  • this关键字总是指向该方法的对象。

    • 当this出现在构造方法中,this指的是该构造器正在初始化的对象,(也就是最外层的)
    • 在普通方法中引用,this指的是调用该方法的对象
  • 作用:this关键字最大的作用就是让类中一个方法,访问该类里的另一个方法或Field

final关键字
  • final关键字可以修饰类,可以修饰变量,可以修饰方法:

    • 修饰类,类不能被继承

    • 修饰变量,变量就变成了常量,只能被赋值一次 当修饰的变量是一个对象时,该对象不能改变(即不能将变量更改为另一个对象),但是对象中的内容可以改变

      • 如:final StringBuffer a=new StringBuffer("abc");

        ? 执行 a=new StringBuffer(""); 会报错,因为又重新New了一个对象

        ? 但是执行 a.append("123"); 不会报错,因为对象没有改变,对象的内容发生变化是不影响的

    • 修饰方法,方法不能被重写

通过set方法对对象进行初始化:

代码: public void setSex(String sex){

? this.sex=sex;

? }

小结:
  • 变量—————— 类对应的属性
  • 构造方法——————new对象的时候对对象初始化
  • 方法(函数)——————功能性的方法
封装打包学生类的代码:

Demo demo=new Demo();

Student student=new Student("tom",18,6,"3333","男");

demo.save(student);

public void save(Student student){

? System.out.println(student.getName());

? System.out.println(student.getAge());

}

匿名对象

如上:Demo demo=new Demo();

? demo.save(new Student());

  • new Student只用到一次,没有给他起名字,这就是匿名对象
值传递
  • JAVA的参数传递方式只有一种,那就是值传递

  • 值传递含义:就是将实际参数的复制品传进方法,也就是重新创建一个一模一样的参数,对这个复制品进行方法操作,而实际参数的本身并没有受到影响。

    如:int a=5,b=5;

    ? public void change(int a, int b){
    ? a=100;

    ? b=100;

    ? }

    public void change(int a, int b){
    					a=100;
    					b=100;
    		}
    
    public static void main(){
    	int a=10;
    	change(a);
    		System.out.println(a);
    }
    //打印后a的值依旧是10,调用方法并没有改变,因为传进去的是基本类型的副本,只有引用类型才会传进地址,最后的值会被改变,如果用change方法改变a的值的话,需要在后面return
    

    传进的是引用类型时:

    • public void change(StringBuffer buffer){
      					buffer.append("123");
      		}
      public static void main(){
      	StringBuffer buffer=new StringBuffer("ABC");
      	change(buffer);
      	System.out.println(buffer);
      }
      //此时打印后结果为ABC123,因为传进去的是地址,原本的值会被修改
      

    在此次方法操作中,a和b的值依旧是5,并没有变成100,就是对a与b的复制品进行了操作,实际参数本身没有改变

    如果想要将ab变成100的话,就需要返回a与b,在后面加return ,并将void改为Int

  • 只有基本类型的值传递才是将复制品传进方法,其他类型的值传递是传进地址值的复制品,所以是可以对实际参数进行修改的

重载
  • 方法名不可以重名,但是方法名相同时,参数列表不同时,如:方法一有两个参数,方法二有三个参数,尽管两个方法名字相同,但是可以同时存在,这叫方法的重载

  • 重载只与方法名和参数名称有关,与权限修饰符,返回值类型等无关

  • 方法名相同,参数名称不同或参数数量不同时,才叫重载

递归
  • 含义:自己调用自己

  • 斐波那契数列:

    • 1 1 2 3 5 8 13 21 34

    • 假设要求第n位的值:

      public int fb(int n){

      ? if(n1 || n2){

      ? return 1;

      ? }else{

      ? return fb(n-1)+fb(n-2);

      ? }

      }

  • 递归最重要的是找到第一个递归的出口

Static
  • 特点:

    • static是跟随类的出现而出现,类名出现一次,那么static后面的内容就会执行一次

    • 被类的所有对象(new一次就是一个对象)共享:在调用static修饰的变量时,不同对象调用的是同一个变量,对象一对变量b进行改变时,对象二中的变量b也会改变而不同的对象调用不被static修饰的变量时,不同的对象使用的是不同的变量,对象一修改变量a时,对象二的变量a是不会被改变的

    • 例如:

      • static int a=1;
        public static void main(){
        	Num num1=new Num();
        	Num num2=new Num();
        	num1.a=2;
        	System.out.println(num2.a)
        }
        //此时打印的num2的a,它的值为2,因为两个对象共用的一个变量,num1做了修改,num2也会有改变
        
    • 可以通过类名直接调用

  • 注意事项

    • 在静态方法中不可以使用this关键字 因为this关键字总是指向该方法的对象,静态方法是随着类的出现而出现,不需要New出对象,所以在静态方法中,没有对象是无法使用this的
    • 静态方法里不能访问成员变量或成员方法 因为静态方法是随着类的出现而出现,成员变量需要先New出对象,才能访问得到
  • 静态变量和成员变量的区别

    • 所属不同
      • 静态变量属于类,所以也称为为类变量
        成员变量属于对象,所以也称为实例变量(对象变量)
      • 内存中位置不同
        静态变量存储于方法区的静态区
        成员变量存储于堆内存
      • 内存出现时间不同
        静态变量随着类的加载而加载,随着类的消失而消失
        成员变量随着对象的创建而存在,随着对象的消失而消失
      • 调用不同
        静态变量可以通过类名调用,也可以通过对象调用
  • 用武之地

    • 使用工具方法时,可以加static,因为每次使用工具都需要New出对象,过于麻烦,而加上static后,只需要使用类的名字直接用点就可以调用,不需要new对象
    • 只需加载或执行一次
代码块:
  • 局部代码块:

    • 出现在方法的内部,用大括号括起来的就是局部代码块
    • 定义在局部代码块内的变量,出了局部代码块后,外面的访问不到
    • 限定变量生命周期,及早释放,提高内存利用率
  • 构造代码块

    • 在类中方法外出现;多个构造方法中相同的代码存放到一起,每次调用构造都执行时就可以用构造代码块,并且在构造方法前执行
    • 运用:当所有的构造方法中都有相同的部分时,可以把他放进构造代码块里,这样可以减少构造方法中相同的部分出现
  • 静态代码块

    • 在构造代码块前加上static,构造代码块是New一次,代码块的内容出现一次,静态代码块是类出现一次,就执行一次

继承:

概述:
  • 多个类存在相同的属性和行为时,将这些内容抽取到单独一个类中,那么多个类无需再定义这些属性和行为(也叫方法),只要继承这个类就可以了,这个类就是父类

  • 父类与子类:

    • 父类又叫超类或者基类
    • 子类又叫派生类
  • 通过extends关键字实现继承

    • class 子类名 extends 父类名 {}
继承的好处:
  • 提高了代码的复用性

    • 多个类相同的成员可以放到同一个类中
    • 如:老师和学生同属于人,那么人这个类中定义的姓名,年龄,身高体重这些属性老师和学生都可以使用
  • 提高了代码的维护性

    • 如果功能的代码需要修改,只需修改父类的代码即可
  • 让类与类之间产生了关系,是多态的前提

    • 其实这也是继承的弊端,类的耦合性很强
    • 耦合性:在A类中new一个B类,一旦B类出现问题,那么A类中使用的B类也不能用,或者想要将B类换成C类,要将A类中所有B类的部分全都替换
特点:
  • JAVA只支持单继承,不支持多继承

    • 一个类只能有一个父类
  • JAVA支持多层继承(爷爷类)

    • A继承B B继承C
注意事项:
  • 子类只能继承父类非私有的成员(成员方法和成员变量)

    • 这也是继承的另一个弊端:打破了封装性
  • 子类不能继承父类的构造方法,但是可以通过super关键字去访问父类构造方法

    • 要访问父类的构造就只能通过子类的构造方法去访问

      • //父类的空参构造:
        public Pet(){
        }
        
        //通过子类访问父类构造:
        public Dog(){
        	super();
        }
        
        
        //注:尽管在子类的构造方法中没有写super(); 但是已经默认写上了父类的空参构造
        
        
        
        
        //父类的有参构造:
        public name;
        publci Pet(String name){
        	this.name=name;
        }
        
        //通过子类访问父类的有参构造:
        public Dog(String name){
        	super(name);
        }
        
        
        
    • 子类中所有的构造方法默认都会访问父类空参的构造方法

      • 因为要实现子类的初始化,首先要实现父类的初始化,子类使用的是父类的变量,父类如果没有构造,子类不能使用
    • 不能通过 子类=new 父类

    • 可以通过 父类=new 子类

子类中访问变量的顺序
  • 首先在子类局部范围找
  • 然后在子类成员范围找
  • 最后在父类成员范围找 不能访问父类局部范围
  • 最后还没有就会报错 是不会找爷爷类的
super关键字
  • super的用法和this很像

    • this代表本类对象的引用
    • super代表父类对象的引用
  • super用法:

    • super.变量名 (父类的变量) super.name;
    • super.方法名 (父类的方法) super.eat();
重写(Override):
  • 子类中出现了和父类一模一样的方法声明,也被称为方法覆盖,方法复写

  • 规则:

    • 方法名相同,形参列表相同

    • 子类方法返回值类型应该比父类方法返回值相等或者更小。

      • 返回值类型比父类的要小,这两个返回值一定要有父子关系才行
      • 基本类型之间没有父子关系
    • 子类方法声明抛出的异常应该比父类方法更小或者相等

    • 子类权限比父类权限大或者相等

  • 补充:

    • 子类重写了父类的方法后,子类对象无法访问父类中被覆盖的方法,但可以在子类方法中调用父类被重写的方法,需要使用super关键字
    • 如果父类的方法啊具有private权限修饰符,则该方法是对子类隐藏的,也就是无法重写该方法
      • 如果子类中定义了一个与父类private方法 相同的方法名、形参列表、返回值类型,这依然不是重写,只是在子类重新定义了一个新方法而已
    • 子类重写父类方法时,访问权限不能更低
      • 如:父类方法用 protcted修饰,那么子类的修饰符只能更大或者一致,也就是只可以用public 或者protcted修饰
    • 父类静态方法,子类也必须经过静态方法进行重写
      • 这个不算重写,但是表现出的现象确实如此
      • 因为静态不属于继承的范围,静态与类挂钩,与对象无关
常量的权限修饰:
  • 任何一个常量都是被public static final修饰
    • public 保证可以访问到
    • static 表示是跟着类出来的 (通过类来选)
    • final 表示不能更改
一个类的初始化顺序:
  • 先初始化静态变量,静态方法
  • 执行静态代码块
  • 执行构造代码块
  • 执行构造方法

多态

  • 一个事物在不同时刻表现出来的不同状态
多态的前提和体现:
  • 有继承关系

  • 有方法的重写

  • 有父类引用指向子类对象

  • 举例:

    • Pet pet=new Dog();
      pet.eat();
      
      Pet pet=new Cat();
      pet.eat();
      
    • new Dog时打印出狗吃骨头,new Cat时打印出猫吃鱼

多态的好处:
  • 对外管理的是同样的pet对象,具体New哪一个类,在后面改就可以

    • 在大型项目中,后面用父类具体new哪一个子类,是不用在代码里写的,用配置文件配置就好了
    • 这叫做解耦,代码与代码之间的耦合性降低
  • 提高了程序的维护性

  • 提高了程序的扩展性

    • 在定义方法时,传进的参数只需传一个父类就代表随意传子类了,具体想要传哪一个子类,只需在父类new子类的时候,改成想要new的那个子类就可以,形参是不需要动的
多态的弊端:
  • 不能访问子类特有功能
  • 想要访问子类特有功能只能转型
instanceof关键字
  • A类 instanceof B类

    • A类是否是B类的子类
  • A类 instanceof A类

    • 这也是可以的
成员访问的特点:
  • 访问变量时,访问的是父类的变量

  • 访问方法时,访问的是子类的方法

    • 但是父类中要有和子类方法一样的方法名

      • 如: 子类Dog类中有play这个方法,但是父类Pet类中没有该方法,所以是无法使用Dog类的play方法的

      • 这就是多态的弊端:无法访问子类特有的功能

        • play方法是Dog类特有的功能,父类Pet类没有,所以访问不到
      • 解决方法:转型

        • public static void change(Pet pet){
          	if(pet instanceof Dog ){
          		pet=(Dog)pet;
          		((Dog)pet).play();
          	}
          	if(pet instanceof Cat){
          		pet=(Cat)pet;
          		((Cat)pet).play();
          	}
          }
          
  • 访问静态方法时,访问的是父类

抽象类

  • 抽象就是找出事物的相似和共性之处,然后将然后将这些事物归为一个类,这个类只考虑这些
    事物的相似和共性之处,并且会忽略与当前主题和目标无关的那些方面,将注意力集中在与
    当前目标有关的方面

  • 当一个类没有具体信息,只是定义一些功能(就是要干嘛能干嘛),那么就把这个类定义为抽象类

定义格式:
  • 抽象类和抽象方法必须用abstract关键字修饰
    • abstract class 类名 {}
    • public abstract void eat();
特点:
  • 抽象类不一定有抽象方法,有抽象方法的类一定是抽象类

    • 抽象类中有具体方法,是为了提高代码的复用性
      • 抽象类可以有一些共有的工具方法,这些方法对所继承的所有子类来说都是一样的,或者是不变的、唯一的,那么就可以加在抽象类中大家一起去用
      • 子类所特有的一些东西,在抽象类中只定义一个抽象方法,具体的实现由子类自己去重写
  • 抽象类不能够被实例化

    • 抽象类的实例化是通过多态来实例化
    • 这也是多态的一种,抽象类多态
  • 抽象类的子类:

    • 抽象类的子类必须重写抽象类的所有抽象方法
    • 如果子类没有实现抽象父类的所有抽象方法,那么子类也必须定义为抽象类
成员特点:
  • 成员变量:

    • 可以是变量
    • 可以是常量
  • 构造方法:

    • 抽象类可以有构造方法,但是不能够被实例化
    • 构造方法的作用就是用于子类访问父类数据的初始化
      • 抽象类的抽象方法是要被子类重写的,是要有继承关系的,所以抽象类的构造方法的作用就是让子类去访问的,但是抽象类本身是不能够被实例化,不能new出抽象类这个对象,但是它的构造方法会被执行一下
    • 抽象类不能有抽象构造方法和抽象静态方法
  • 成员方法:

    • 抽象方法:限定子类必须完成某些行为
    • 非抽象方法:提高代码的复用性
abstract关键字不能与哪些关键字共存:
  • private 冲突

    • 定义为抽象方法一定是要被子类重写的,那么如果将抽象方法定义为private子类都访问不到,重写个锤子
  • final 冲突

    • 与上同,final修饰的方法不可以被重写
  • static 无意义

    • 抽象类要被继承,继承与对象挂钩,对象是后出现的,而static是随着类的出现而出现,继承不到static方法

接口

  • 接口是在抽象类的基础上出现的,接口限定的是行为,方便代码的扩展
格式:
  • 定义一个类为接口:

    • public interface UserService{
      	public void insert();
      	
      	public void delete();
      }
      
  • 用一个类实现一个接口:用   implements

    • public class UserService implements UserService{
      	public void insert(){
      	
      	}
      	
      	public void delete(){
      	
      	}
      }
      
特点:
  • 对于变量来说:

    • 只能是常量
    • 且常量的默认修饰符:public static final
      • 接口是一个规范,是不能被改变的,所以一定是常量,被final修饰,如果可以更改的话,这个规范没有意义,就不叫规范
  • 对于方法来说:

    • 只能是抽象方法
    • 且抽象方法的默认修饰符:public abstract
  • 对于构造方法:

    • 接口没有构造方法
    • 接口主要做功能拓展的,没有具体实现
  • 接口不能被实例化

    • 要实例化接口,就要按照多态的方式
    • 这也是多态的一种,叫接口多态
  • 接口的子类

    • 必须重写接口中的所有抽象方法

接口和抽象类的差异

  • 抽象类是一个类,子类要继承(extends)它, 接口是要被子类实现(implements),关键字不同

  • 对于变量:

    • 抽象类可以有普通成员变量,接口没有普通成员变量
      • 接口的变量只能为常量,默认被public static final修饰
  • 对于成员方法:

    • 抽象类里可以有非抽象的方法,但是接口里必须全都是抽象方法
    • 抽象类的方法可以包含静态方法,接口不能包含静态方法
      • 接口的抽象方法只能是,并且默认是:public abstract
  • 对于构造方法:

    • 抽象类可以有构造方法,接口不能有构造方法
  • 一个类可以实现多个接口,但只能继承一个抽象类

面向对象的特征(封装、继承、多态、抽象)

上一篇:使用 SharedPreferences 实现数据的存储和读取


下一篇:关于sessionStorage的使用总结