继承的特点
- 子类可以继承父类的属性和行为,但是子类不能继承父类的构造器。
- Java是单继承模式:一个类只能继承一个直接父类。
- Java不支持多继承、但是支持多层继承。
- Java中所有的类都是Object类的子类。
- 子类可以继承父类的私有成员但是不能直接访问
枚举
方法重写注意事项和要求
- 重写方法的名称、形参列表必须与被重写方法的名称和参数列表一致。
- 私有方法不能被重写。
- 子类重写父类方法时,访问权限必须大于或者等于父类 (缺省 < protected < public)
- 子类不能重写父类的静态方法,如果重写会报错的。
final修饰的特点:
- 修饰方法:表明该方法是最终方法,不能被重写
- 修饰变量:final修饰的变量是基本类型:那么变量存储的数据值不能发生改变。final修饰的变量是引用类型:那么变量存储的地址值不能发生改变,但是地址指向的对象内容是可以发生变化的。
- 修饰类:表明该类是最终类,不能被继承
static修饰的特点:
- 被类的所有对象共享(也即唯一)–这也是我们判断是否使用静态这个关键字的条件
- 可以通过类名调用,当然也可以通过对象名调用
- 被静态修饰的方法,只能访问静态成员变量和静态成员方法,即只能访问静态成员
多态:不同的子类对象调用相同的父类方法而产生不同的结果
注意:
1、如果是父类对象调用父类中的成员变量,即使是在多态这种情况下结果依然是输出父类的成员变量中的值,而不是子类成员变量中的值,因为子类并没有重写父类中的成员变量。
2、多态的情况下父类依然是不能调用子类中独有的成员方法和成员变量。
多态的好处:提高了程序的扩展性
具体体现是:定义方法的时候,使用父类型作为参数,将来在使用的时候,使用具体的子类型参与操作。
多态的弊端:不能使用子类的特有功能
多态转型:
向上转型:父类引用指向子类对象
Animal a = new Cat()
不能调用子类方法和子类属性
向下转型:父类引用转为子类对象
Animal a = new Cat()
Cat c = (Cat) a
可以调用子类方法和子类属性
抽象类:
public abstract class Animal{ // 抽象类
public abstract void run(); // 抽象方法
}
在Java中,一个没有方法体的方法应该被定义为抽象方法,而类中如果有抽象方法,则该类必须被定义为抽象类,抽象类中可以拥有非抽象方法。
抽象类不能被直接实例化,可以参照多态的方式,通过子类对象实例化,这叫抽象类多态
抽象类的子类:要么重写抽象类中的所有抽象方法,要么是抽象类。
final和abstract的关系
- 互斥关系
- abstract定义的抽象类作为模板让子类继承,final定义的类不能被继承。
- 抽象方法定义通用功能让子类重写,final定义的方法子类不能重写。
接口:
接口用关键字interface来定义
public interface 接口名 {
// 常量
// 抽象方法
}
2、类实现接口用implements:
public class 类名 implements 接口名 {}
3、接口不能实例化 即不能new接口
接口如何实例化?参照多态方式,通过实现类对象实例化,这叫接口多态。
多态的形式:具体类多态,抽象类多态,接口多态。
多态的前提:有继承或者实现关系;有方法重写;有父(类/接口)引用指向(子/实现)类对象。
接口的实现类:要么重写接口中的所有抽象方法,要么是抽象类
4、接口中的成员都是public修饰的,写不写都是,因为规范的目的是为了公开化。
接口的成员特点:
1、成员变量只能是常量即以public static final开头修饰的,如果没写则默认以public static final开头
2、构造方法:接口没有构造方法,因为接口主要是对行为进行抽象的,是没有具体存在的
3、成员方法:只能是抽象方法即默认以public abstract开头即使不写也是以public abstract开头
抽象类和接口的区别:
1、成员区别:
- 抽象类:有变量,常量;有构造方法,有抽象方法,也可以有非抽象方法;
- 接口:只有常量,抽象方法;
2、关系区别:
- 类与类:之间只能是单继承;
- 类与接口:可以单继承单实现,可以但单继承多实现;
- 接口与接口:可以单继承,也可以多继承
3、设计理念区别:
- 抽象类:对类抽象包括行为和属性;
- 接口:对行为抽象,主要是行为;
内部类的访问特点:
1、内部类可以直接访问外部类的成员,包括私有成员;
2、外部类想要访问内部类的成员必须创建对象;
创建内部类对象格式:
外部类.内部类 对象名 = new 外部类名().new 内部类名();
静态内部类:
外部类.内部类 对象名 = new 外部类名.内部类名();
匿名内部类:
Employee a = new Employee() {
public void work() {"干自己的事情"}
};
a. work();
-----------------------------------------------------------
package com.scanner;
public class Demo {
public static void main(String[] args) {
new Test(){
@Override
public void test() {
System.out.println("测试");
}
}.test();
}
}
interface Test {
void test();
}
匿名内部类特点:
- 匿名内部类是一个没有名字的内部类,同时也代表一个对象。
- 匿名内部类产生的对象类型,相当于是当前new的那个的类型的子类类型。
- 匿名内部类可以作为一个对象,直接传输给方法。
lambda:
package com.scanner;
public class Demo {
public static void main(String[] args) {
test_anonymous_class(()->{
System.out.println("测试lambda和匿名内部类1");
});
// 光标放到Test上按下option+回车会提示用lambda替换掉匿名内部类
test_anonymous_class(new Test() {
@Override
public void test() {
System.out.println("测试lambda和匿名内部类2");
}
});
}
public static void test_anonymous_class(Test test){
test.test();
}
}
interface Test {
void test();
}
lambda的使用前提:
- 有个接口
- 接口中有且仅有一个抽象方法
lambda 和匿名内部类的区别:
1、所需类型不同:
- 匿名内部类:可以是接口,也可以是抽象类,还可以是具体类
- lambda表达式:只能是接口
2、使用限制不同:
- 如果接口中有且仅有一个抽象方法,可以使用lambda表达式,也可以使用匿名内部类
- 如果接口中多于一个抽象方法,只能使用匿名内部类,而不能使用lambda表达式
3、实现原理不同:
- 匿名内部类:编译之后,产生一个单独的.class字节码文件
- lambda表达式:编译之后,没有一个单独的.class字节码文件,对应的字节码会在运行的时候动态生成
Lambda表达式的省略写法(进一步在Lambda表达式的基础上继续简化)
- 参数类型可以省略不写。
- 如果只有一个参数,参数类型可以省略,同时()也可以省略。
- 如果Lambda表达式的方法体代码只有一行代码。可以省略大括号不写,同时要省略分号!
- 如果Lambda表达式的方法体代码只有一行代码。可以省略大括号不写。此时,如果这行代码是return语句,必须省略return不写,同时也必须省略";"不写