java学习笔记:java基础之面向对象

Java类及类的成员:属性、方法、构造器;代码块、内部类

面向对象三大特征:封装性、继承性、多态性、(抽象性)

其他关键字:this , super , static , final , abstract , interface , package , import

面向对象和面向过程的对比

面向过程:强调的是功能行为,以函数为最小单位,考虑怎么做

面向对象:强调具备了功能的对象,以类\对象为最小单位,考虑谁来做

属性(成员变量) vs 局部变量:

  1. 相同点:

    1. 定义变量格式相同:数据类型 变量名 = 变量值
    2. 先声明后使用
    3. 变量都有其对应的作用域
  2. 不同点:

    1. 在类中声明的位置不同

      属性:直接定义在类的一对{}中

      局部变量:声明在方法内、方法形参、代码块内、构造器形参、构造器内部的变量

    2. 关于权限修饰符不同

      属性:可以在声明属性时指明其权限,使用权限修饰符

      • 常用的权限修饰符:private , public , 缺省 , protected ----> 封装性

      局部变量:不可以使用权限修饰符。

    3. 默认初始化值:

      1. 属性:类的属性,根据其类型,都有默认初始化值。

        1. 整型(byte 、 short、 int、 long) 0
        2. 浮点型(float、double) 0.0
        3. 字符型(char) 0(或'\u0000')
        4. 布尔型(boolean) false
        5. 引用数据类型(类,数组,接口) null
      2. 局部变量 : 没有默认初始化值

        意味着我们在使用局部变量前一定要显性赋值。

        特别的,形参在调用时,我们赋值即可

    4. 在内存中加载的位置

      1. 属性:加载到堆空间中(非static)
      2. 局部变量:加载到栈空间中

内存解析的说明:

引用类型的变量,只可能储存两类值:null 或 地址值(含变量的类型)

匿名对象的使用:

  1. 理解:我们创建的对象,没有显示的赋给一个变量名,即为匿名对象
  2. 特征:匿名对象只能调用一次

再谈方法:

方法的重载(overload) : loading

  1. 定义 : 在同一个类中,允许存在一个以上的同名方法,只要他们的参数个数或者参数类型不同即可。

    两同一不同 : 用一个类 , 同一个方法名

    ​ 参数列表不同:参数个数不同,参数类型不同

  2. 判断是否是重载:

    • 与方法的权限修饰符、返回值类型、形参变量名、方法体都没有关系。
  3. 在通过对象调用方法时,如何确定某一个指定的方法:

    方法名 -----> 参数列表

可变个数形参的形式

允许直接定义一个

具体使用:

  1. 数据类型 ... 形参
  2. 当调用可变个数形参的方法时,传入的参数个数可以是0个,1个 , 2个 , 多个...
  3. 可变个数形参的方法与本类中方法名相同,形参不同的方法之间构成重载
  4. 可变个数形参的方法与本类中方法名相同,形参类型也相同的数组之间不构成重载。换句话说,二者不能共存
  5. 可变个数形参在方法的形参中,必须声明在末尾
  6. 可变个数形参在方法的形参中,最多只能声明一个。
public void show(String ... strs){
    
}

方法的形参的传递机制:值传递

  1. 形参:方法定义时,声明的小括号内的参数

    实参:方法调用时,实际传递给形参的数据

    • 如果参数是基本数据类型,此时实参赋给形参的是真实储存的数据值
    • 如果参数是引用数据类型,此时实参赋给形参的是实参储存数据的地址值。

递归方法 : 一个方法体内调用它本身

  1. 方法递归包含了一种隐式的循环,他会重复执行某一段代码,但这种重复执行不需要循环控制。
  2. 递归一定要向已知方向递归,否则这种递归就成了无穷递归,类似于死循环。
public  class RecursionTest{
    public static void main(String[] args){
        RecursionTest test = new RecursionTest();
        int sum1 = test.getSum(100);
        System.out.println(sum1);
    }
	/* 
	//计算1-100所有自然数的和
    int sum = 0;
    for(int i=0;i<100;i++) sum += i;
    */
    public int getSum(int n){
        if(n == 1) return 1;
        else return n+getSum(n-1);
    }
}

面向对象特征之封装和隐藏

封装性的体现:

我们将类的属性×××私有化(private),同时,提供公共的(public)方法来获取(get×××) 和设置(set×××)

高内聚:类的内部数据操作细节自己完成,不允许外界干涉;

低耦合:仅对外暴露少量的方法用于使用

封装性的体现,需要权限修饰符的配合。

  • java的规定的4种权限(从小到大):private , 缺省 , protected , public

  • 4种权限可以用来修饰类的内部结构:属性、方法、构造器、内部类

  • 具体的,4种权限都可以用来修饰类的内部结构:属性、方法、构造器、内部类

    ​ 修饰类的话,只能使用 缺省 , public

  • 总结:java提供了4种权限修饰符来修饰类以及类的内部结构,体现类及类的内部结构在调用时的可见性的大小

类的成员之:构造器(或构造方法 、 constructor)

构造器的作用:

  1. 创建对象
  2. 初始化对象的属性

说明:

  1. 如果没有显示的定义类的构造器的话,则系统默认提供一个空参的构造器
  2. 定义构造器的格式:权限修饰符 类名(形参列表){}
  3. 一个类中定义的多个构造器 , 彼此构成重载
  4. 一旦显式定义了类的构造器之后,系统就不再提供默认的空参构造器
  5. 一个类中,至少会有一个构造器
public class PersonTest{
    public static void main(String[] args){
        // 创建对象时会调用构造器
        Person p = new Person();
        
        p.eat();
    }
}
class Person{
    String name;
    int age;
    // 构造器
    public Person(){
        
    }
    public void eat(){
        System.out.println("人吃饭");
    }
    public void study(){
        System.out.println("在学习");
    }
}

属性赋值的先后顺序:

  1. 默认初始化
  2. 显示初始化 、代码块中赋值
  3. 构造器中赋值
  4. 通过“对象.方法”或“对象.属性”的方式赋值

关键字:this 的使用

  1. this可以用来修饰、调用:属性、方法、构造器

  2. this 修饰属性、方法:this理解为当前对象

    1. 在类的方法中,我们可以使用“this.属性” 或 “this.方法”的方式,调用当前对象的属性或方法。但是,通常情况下,我们都选择省略"this."。特殊情况下,如果方法的形参和类的属性同名时,我们必须显式的使用“this.变量”的方式,表明此变量是属性,而非形参。
    2. 在类的构造器中,我们可以使用“this.属性” 或 “this.方法”的方式,调用当前正在创建的对象属性或方法。但是,通常情况下,我们都选择省略"this."。特殊情况下,如果构造器的形参和类的属性同名时,我们必须显式的使用“this.变量”的方式,表明此变量是属性,而非形参。
  3. this 修饰构造器:

    1. 在类的构造器中,可以显式的使用“this(形参列表)”的方式,调用本类中指定的其它构造器。

    2. 构造器中不能通过“this(形参列表)”方式调用自己

    3. 如果一个类中有n个构造器,则最多有n-1个构造器中使用了“this(形参列表)”

    4. 规定:“this(形参列表)”必须声明在当前构造起的首行
    5. 构造器内部,最多只能声明一个“this(形参列表)” , 用来调用其他的构造器。

关键字 : package and import

  1. package 关键字的使用:

    1. 为了更好地实现项目中类的管理,提供包的概念
    2. 使用package 声明类或接口所述的包,声明在源文件的首行
    3. 包,属于标识符,遵循标识符的命名规则和规范,“见名知意”
    4. 每 “ . ” 一次,就代表一层文件目录。
    5. 补充:同一个包下,不能命名同名的接口、类
  2. import 关键字的使用:

    1. 在源文件中显式的使用import结构导入指定包下的类、接口

    2. 声明在包的声明和类的声明之间

    3. 如果需要导入多个结构,则并列写出即可

    4. 可以使用“×××.*“的方式,表示可以导入×××包下的所有结构

    5. 如果使用的类或接口是java.lang包下定义的,则可以省略import结构

    6. 如果使用的类或接口是本包下定义的,则可以省略import结构

    7. 如果在源文件中,使用了不同包下的同名的类,则必须至少有一个类必须以全类名的方式显示

      Account acct = new Account(1000);
      // 全类名
      com.atguigu.exer3.Account acct1 = new com.atguigu.exer3.Account(1000,2000,0.0123
      
      
    8. 使用“×××.*”方式表明可以调用×××包下的所有结构,但是如果使用的是×××子包下的结构仍需显式调用

    9. import static:导入指定类或接口中的静态结构:属性或方法

面向对象特征之继承性

  1. 继承性的好处

    1. 减少代码的冗余,提高了代码的复用性
    2. 便于功能的扩展
    3. 为资后的多态性的使用,提供了前提
  2. 继承性的格式:

    1. 一旦子类A继承父类B以后,子类A就获取了B种声明的结构:属性、方法。
      特别的,父类中声明为private的属性和方法,子类继承父类以后,仍然认为获取了父类中私有的结构。只是因为封装性的影响,使得子类不能直接调用父类的结构
    2. 子类继承父类以后,还可以声明自己特有的属性或方法,实现功能的拓展
    3. 父类和子类的关系,不同于子集和集合的关系。
    4. extends:延展、扩展
    class A extends B{}
    // A : 子类、派生类、subclass
    // B : 超类 、 基类、superclass
    
  3. Java中关于继承性的规定:

    1. 一个类可以被多个子类继承
    2. Java中类的单继承性,一个类只能有一个父类
    3. 子父类是相对的概念
    4. 子类直接继承的父类,称为直接父类。间接继承的父类称为:间接父类
    5. 子类继承父类以后,就获取了直接父类以及所有间接父类中声明的属性和方法。
  4. 对java.lang.Object 的理解:

    1. 如果我们没有显式的声明一个类的父类的话,则此类继承与java.lang.Object类
    2. 所有的java类(除java.lang.Object类之外)都直接或间接的继承于java.lang.Object类
    3. 意味着,所有的java类具有java.lang.Object类声明的功能.

方法的重写(override/overwrite)

  1. 定义:在子类中可以根据需要对父类继承来的方法进行改造,特成为方法的重置、覆盖。在程序执行时,子类的方法将覆盖父类的方法。

  2. 重写:子类继承父类以后,可以对父类中同名同参数的方法进行覆盖操作

  3. 应用:重写以后,当创建子类对象以后,通过子类对象调用子父类中的同名同参数方法时 ,实际执行的是子类重写父类的方法

  4. 重写的规定:

    1. 方法的声明 : 权限修饰符 返回值类型 方法名(形参列表)[throws 异常的类型]
    2. 约定俗成:子类中的叫重写的方法,父类中的叫被重写的方法
      1. 子类重写的方法的方法名和形参列表与父类中被重写的方法的方法名和形参列表相同
      2. 子类重写的方法的权限修饰符不小于父类被重写的方法的权限修饰符。
        1. 特殊情况:子类不能重写父类中声明为private权限的方法。
      3. 返回值类型:
        1. 父类被重写的返回值类型是void , 则子类重写的方法的返回值类型 只能是void
        2. 父类被重写的方法的返回值类型是A类,则子类重写的方法的返回值类型可以是A类或A类的子类
        3. 父类被重写的方法的返回值类型是基本数据类型,则子类重写的方法的返回值类型必须是相同的基本数据类型。
      4. 子类重写的方法抛出的异常类型不大于父类被重写的方法抛出的异常类型
    3. 子类和父类中同名同参数的方法要么都声明为非static的(考虑重写),要么都声明为static的 (不是重写)

super关键字

  1. super 理解为:父类的

  2. super可以用来调用:属性、方法、构造器

  3. super的使用:

    1. 我们可以在子类的方法或构造器中。通过使用“super.属性”或“super.方法”的方式,显式的调用父类中声明的属性或方法。
    2. 特殊情况:当子类和父类中定义了同名的属性时,我们要想在子类中调用父类中声明的属性,则必须显式的使用“super.属性”的方式,表明调用的是父类中声明的方法
    3. 特殊情况:当子类重写了父类中的方法以后,我们想在子类的方法中调用父类中被重写的方法时,就必须显式的使用“super.方法”的方式,表明调用的是父类中被重写的方法
  4. super调用构造器:

    1. 我们可以在子类的构造器中显式的使用“super(形参列表)”的方式,调用父类中声明的指定的构造器
    2. “super(形参列表)”的使用,必须声明在子类构造器的首行
    3. 我们在类的构造器中,针对“super(形参列表)” 和 “this(形参列表)”只能二选一,不能同时出现
    4. 在构造器的首行,没有显式的声明“super(形参列表)” 和 “this(形参列表)”,则默认调用的是父类中空参的构造器
    5. 在类的多个构造器中,至少有一个构造器中使用了“super(形参列表)”,调用父类的构造器
  5. this(形参列表) : 本类重载的其他的构造器

    super(形参列表) : 调用父类中指定的构造器

子类对象实例化的全过程(了解)

  1. 从结果上来看(继承性):
    1. 子类继承父类以后,就获取了父类中声明的属性或方法
    2. 创建子类的对象,在堆空间中,就会加载所有父类中生命的属性
  2. 从过程上看:
    1. 当我们通过子类的构造器创建子类对象时,我们一定会直接或间接的调用父类的构造器,仅为调用父类的父类的构造器,知道调用了java.lang.Object类中的空参构造器位置。正因为加载过所有的父类的结构,所以才可以看到内存中有父类中的结构,子类对象才可以考虑进行调用
  3. 明确,虽然创建子类对象时,调用了父类的构造器,但是自始至终就创建过一个对象,即为new的子类对象

面向对象特征之多态性

  1. 理解多态性:可以理解为一个事物的多种形态
  2. 何为多态性:对象的多态性:父类的引用指向子类的对象(或子类的对象赋给父类的引用)
  3. 多态的使用:虚拟方法调用
    1. 有了对象的多态性以后,我们在编译期,只能调用父类中声明的方法,但在运行期,我们实际执行的是子类重写父类的方法。
    2. 子类中定义了与父类同名同参数的方法,再多态情况下,将此时父类的方法称为虚拟方法(也称虚方法),父类根据赋予他的不同子类对象,动态调用属于子类的该方法。这样的方法调用在编译期是无法确定的。
  4. 多态的适用前提:
    1. 类的继承关系
    2. 方法的重写
  5. 对象的多态性,只适用于方法,不适用于属性
/*
--> Object
    --> Person
     	--> Woman  
    	--> Man
*/
// 总结:编译看左边,运行看右边 :编译看的是Person 运行看的是Man or Woman
Person p2 = new Man();
Person p3 = new Woman();
// 都是多态
// 多态示例:
public class AnimalTest{
    public static void main(String[] args){
        AnimalTest test = new AnimalTest();
        test.func(new Dog());
        /*
        狗吃骨头
        汪汪汪
        */
        
    }
    public void func(Animal animal){
        animal.eat();
        animal.shout();
    }
}
class Animal{
    public void eat(){
        System.out.println("动物,进食");
    }
    public void shout(){
        System.out.println("动物 , 叫");
        
    }
}
class Dog extends Animal{
    public void eat(){
        System.out.println("狗吃骨头");
    }
    public void shout(){
        System.out.println("汪汪汪");
        
    }
}
class Cat extends Animals{
    public void eat(){
        System.out.println("猫吃鱼");
    }
    public void shout(){
        System.out.println("喵喵喵");
        
    }
}
调用子类特有的属性和方法:—— 向下转型:强制类型转换
  • 有了对象的多态性以后,内存中实际上是加载了子类特有的属性和方法,但是由于变量声明为父类的类型,导致编译时只能调用父类中声明的属性和方法。子类特有的属性和方法不能调用
  • 如何实现向下转型:使用() 强制类型转换福

instanceof 操作符

x instanceof A x是A的实例返回true 否则 返回false

  • x 是一个对象或称为对象的引用
  • A 是一个类型

使用情景;为了避免向下转型出现ClassCastException异常,我们在向下转型之前,先进行instanceof的判断,一旦返回true 就向下转型,否则不进行

if(p2 instanceof Woman){
    Woman w1 = (Woman)p2;
}
// 编译通过,运行不过
Person p3 = new Woman();
Man m3 = (Man)p3;
// 编译过,运行过
Object obj = new Woman();
Person p = (Person)obj;

// 编译不过
Man m5 = new Woman();
// 右边的类必须是左边的子类
public class InterviewTest1{
    public static void main(String[] args){
        Base1 base = new Sub1();
        base.add(1,2,3);
    }
}

class Base1 {
    public void add(int a , int ... arr){
        System.out.println("base1");
            
    }
}

class Sub1 extends Base1{
    public void add(int a,int[] arr){
        System.out.println("sub_1");
       
    }
    public void add(int a , int b , int c){
        System.out.println("sub_2");
    }
}

// >>> sub_1
// 执行顺序 : 编译:执行Base1中的 add方法
// 			运行:执行Sub1 中的重写的方法,而 int ... arr 对应 int[] arr 所以输出 sub_1 而非 sub_2

java.lang.Object类

  1. Object类是所有java类的根父类
  2. 如果在类的声明中未使用extends关键字知名其父类,则默认父类为java.lang.Object类
  3. Object类中的功能(属性、方法)就具有通用性
    • 方法:equals() / toString() / getClass() / hashCode() / clone() / finalize() / wait() / notify() / notifyAll()
  4. Object类只声明一个空参的构造器。

== 和 equals() 的区别

== 运算符:

  1. 可以使用在基本数据类型变量和引用数据类型变量中
  2. 如果比较的是基本数据类型变量,比较两个变量保存的数据是否相等(不一定类型要相同)
  3. 如果比较的是引用数据类型变量,比较两个变量保存的地址值是否相同,即两个引用是否指向同一个对象实体(不一定类型要相同)
  4. 补充:== 符号使用时,必须保证符号左右两边的变量类型一致

equals() 方法的使用:

  1. 是一个方法而非运算符

  2. 只能适用于引用数据类型

  3. Object 类中equals()的定义:

    public boolean equals(Object obj){
    	return (this == obj);
    }
    

    说明 Object类中定义的equals()和 == 的作用是相同的,比较两个对象的地址值是否相同,即两个引用是否指向同一个对象实体

  4. 像String、Date、File 、 包装类 等都重写了Object类中的equals()方法。重写以后,比较的不是两个引用的地址是否相同,而是比较两个对象的“实体内容”是否相同

  5. 通常情况下,我们自定义的类如果使用equals()的话,也通常是比较两个对象的“实体内容”是否相同,那么我们就需要对Object类中的equals()进行重写

  6. 重写原则:比较两个对象的实体内容(即:name 和 age)是否相同

搜狗截图20200616204116

Object 类中的toString() 的使用:

  1. 当我们输出一个对象的引用时,就已经调用了当前对象的toString()

  2. Object类中toString()的定义

    public String toString(){
        return getClass().getName() + "@" + Integer.toHexString(hashCode());
    }
    
  3. 像String 、 Date、 File、包装类等都重写了Object类中的toString() 方法。使得在调用对象的toString()时,返回了“实体内容”信息

  4. 自定义类也可以重写toString()方法,当调用此方法时,返回对象的“实体内容”

关键字 static

  1. static : 静态的

  2. static可以用来修饰:属性、方法、代码块、内部类

  3. 使用static修饰属性:静态变量(类变量)

    1. 属性,按是否使用static修饰又分为:静态属性 vs 非静态属性(实例变量)

      1. 实例属性:我们创建了类的多个变量,每个对象都独立的拥有一套类中的非静态属性,当修改其中一个对象中的非静态属性时,不会导致其他对象中相同的属性值的修改
      2. 静态变量:我们创建类的多个对象,多个对象共享同一个静态变量,当通过某一个对象修改静态变量时,会导致其他对象调用此静态变量时,是修改过了的
    2. static修饰属性的其他说明:

      1. 静态变量随着类的加载而加载,我们可以通过“类.静态变量”的方式进行调用

      2. 静态变量的加载要早于对象的创建

      3. 由于类只会加载一次,则静态变量在内存中也只会存在一份,存在于方法区的静态域中。

        ​ 类变量 实例变量

        ​ 类 yes no

        ​ 对象 yes yes

      4. 静态属性举例:System.out 、 Math.PI

  4. 使用static修饰方法: 静态方法

    1. 随着类的加载加载,可以通过“类.静态方法”的方式进行调用

      ​ 静态方法 非静态方法

      ​ 类 yes no

      ​ 对象 yes yes

    2. 静态方法中,只能调用静态的方法或属性

    3. 非静态方法中,既可以调用非静态的方法或属性,也可以调用静态的方法或属性

  5. static的注意点

    1. 在静态的方法内,不能使用this关键字,super关键字
    2. 关于静态属性和静态方法的使用,从生命周期的角度去理解
  6. 确定一个属性是否需要声明为static的:

    1. 属性可以被多个对象所共享,不会随着对象的不同而不同的
    2. 类中的常量也常常声明为static
  7. 确定一个方法是否需要声明为static的:

    1. 操作静态属性的方法通常设置为static的
    2. 工具类中的方法,习惯上声明为static的,比如:Math , Arrays , Collections

类的成员之——代码块(或初始化块)

  1. 作用:用来初始化类、对象
  2. 代码块如果有修饰的话,只能用static
  3. 分类:静态代码块 vs 非静态代码块
  4. 静态代码块
    1. 内部可以有输出语句
    2. 随着类的加载而执行
    3. 作用:初始化类的信息
    4. 如果一个类中定义了多个静态代码块,则按照声明的先后顺序执行
    5. 静态代码块的执行要优先于非静态代码块的执行
    6. 静态代码块内只能调用静态的属性、静态的方法、不能调用非静态的结构
  5. 非静态代码块
    1. 内部可以有输出语句
    2. 随着对象的创建而执行,没造一个对象就执行一次
    3. 没创建一个对象,就执行一次非静态代码块
    4. 作用:可以在创建对象时,对对象的属性等进行初始化
    5. 如果一个类中定义了多个非静态代码块,则按照声明的先后顺序执行
    6. 非静态代码块内可以调用静态的属性、静态的方法、或非静态的属性、非静态的方法

关键字:final

final : 最终的

  1. final 可以用来修饰的结构:类、方法、变量
  2. final 用来修饰一个类:此类不能被其他类所继承
    1. 比如:String类、System类、StringBuffer类
  3. final 用来修饰一个方法:此方法不能被重写
    1. 比如:Object类中getClass()
  4. final 用来修饰一个变量:此时的“变量”就成为是一个常量
    1. final修饰一个属性:
      • 可以考虑赋值的位置有:显示初始化、代码块中初始化、构造器中初始化
    2. final修饰局部变量:
      • 尤其是使用final修饰形参时,表明此形参是一个常量,当我们调用此方法时,给常量形参赋一个实参,一旦赋值以后,就只能在方法体内使用此形参,但不能进行重新赋值
  5. static final 用来修饰:属性、方法
    • 属性:全局常量
    • 方法:使用较少,不能被重写,直接通过类来调用

抽象类与抽象方法

  • 随着继承层次中一个个新子类的定义,类变得越来越具体,而父类则更一般,更通用。类的设计应该保证父类和子类能够共享特征。有时将一个父类设计的非常抽象,以至于他没有具体的实例,这样的类叫做抽象类。
  • 应用:用来模型化那些父类无法确定全部实现,而是由其子类提供具体实现的对象的类。
abstract关键字
  1. abstract:抽象的

  2. abstract可以用来修饰的结构:类、方法

  3. abstract 修饰类:抽象类

    1. 此类不能实例化
    2. 抽象类中一定有构造器,便于子类实例化时调用(涉及:子类对象实例化的全过程)
    3. 开发中,都会提供抽象类的子类,让子类对象实例化,完成相关的操作
    public abstract class Person{}
    
  4. abstract 修饰方法;抽象方法

    1. 抽象方法只有方法的声明,没有方法体

    2. 包含抽象方法的类,一定是一个抽象类。反之,抽象类中不一定会有抽象方法。

      • 若子类重写了父类中的所有的抽象方法后此子类方可实例化。
      • 若子类没有重写了父类中的所有的抽象方法,则此子类也是一个抽象类,需要使用abstract修饰
      public abstract void eat();
      
  5. abstract 不能用来修饰:属性、构造器等结构

  6. abstract 不能用来修饰私有方法、静态方法、final的方法

匿名类:

Person p = new Person(){
    @Override
    public void eat(){
        balabala
    }
    @Override
    public void breath(){
        balabala
    }
};

接口:

接口的使用:

  1. 接口使用 interface 来定义

  2. 在java中,接口和类是并列的两个结构

  3. 如何定义接口:定义接口中的成员

    1. JDK7及以前:只能定义全局常量和抽象方法

      1. 全局常量:public static final 的
      2. 抽象方法:public abstract的
    2. JDK8:除了定义全局常量和抽象方法以外,还可以定义静态方法、默认方法

      1. 接口中定义的静态方法,只能通过接口来调用
      2. 通过实现类的对象,可以调用接口中的默认方法。如果实现类重写了接口中的默认方法,调用时,仍然调用的是重写以后的方法。
      3. 如果子类(或实现类)继承的父类和实现的接口中声明了同名同参数的方法,那么子类在没有重写此方法的情况下,默认调用的是父类中同名同参数的方法——类优先原则。
      4. 如果实现类实现了多个接口,而这多个接口中定义了同名同参数的默认方法,那么在实现类没有重写此方法的情况下,报错 ——> 接口冲突 , 这就需要我们必须在实现类中重写此方法
      public interface CompareA{
          // 静态方法
          public static void method1(){
              System.out.println("CompareA:北京");
          }
          // 默认方法
          public default void method2(){
              System.out.println("CompareA:上海");
          }
          default void method3(){
              System.out.println("CompareA:上海");
          }
      }
      
      public class SubClassTest{
          public static void method1(){
              SubClass s = new SubClass();
              // s.methon1(); 报错:没有定义该方法
              CompareA.method1(); // >>> CompareA:北京
              s.method2(); // >>> CompareA:上海
          }
      }
      
      
  4. 接口中不能定义构造器的 意味着接口不可以实例化

  5. java开发中,接口通过让类去实现(implements)的方式来使用。

    如果实现类覆盖了接口中的所有抽象方法,则此实现类就可以实例化

    如果实现类没有覆盖接口中所有的抽象方法,则此实现类仍为一个抽象类

  6. Java类可以实现多个接口 ——> 弥补了java单继承性的局限性

    格式:class AA extends BB inplements CC,DD,EE

  7. 接口与接口之间可以继承,而且可以多继承。

  8. 接口具体的使用能够体现多态性

  9. 接口实际上可以看作是一种规范

类的内部成员之内部类

当一个事物的内部还有一个部分需要一个完整的结构进行描述,而这个内部的完整的结构又只为外部事物提供服务,那么整个内部的完整结构最好使用内部类。

  1. 在java中允许一个类的定义位于另一个类的内部,前者称为内部类,后者称为外部类

  2. 内部类的分类:成员内部类(静态、非静态) vs 局部内部类(方法内、代码块内、构造器内)

    1. 成员内部类:

      1. 一方面作为外部类的成员:

        1. 调用外部类的结构
        2. 可以被static修饰
        3. 可以被4种不同的权限修饰
      2. 另一方面,作为一个类:

        1. 类内可以定义属性、方法、构造器等
        2. 可以被final修饰,表示此类不能被继承。言外之意,不用final ,就可以被继承
        3. 可以被abstract修饰
posted @ 2020-07-10 10:02  abugmaker  阅读(135)  评论(0)    收藏  举报