表示最终的,可以修饰类,成员变量,成员方法
1.final修饰变量成为常量
修饰局部变量: 可以暂时不赋初始值,但是只能够赋值一次
修饰成员变量: 必须给出初始值
2.final修饰的方法不能够被子类重写和继承。
JDK1.8之前的匿名内部类中访问外界的局部变量需要加final,1.8之后不需要
生活中: 同一个动作在不同环境下表现出来的不同状态
Java中: 同一个方法在不同的对象中体现出来不同的状态
内存中: 父类引用指向子类对象
1.简化了代码
2.提高了维护性和扩展性
public class DuoTaiDemo02 {
public static void main(String[] args) {
Fu fu = new Zi();
System.out.println(fu.num); // 10
fu.method();
fu.show();
}
}
class Fu {
int num = 10;
public void method() {
System.out.println("Fu.method()");
}
public static void show() {
System.out.println("Fu.show");
}
}
class Zi extends Fu {
int num = 20;
@Override
public void method() {
System.out.println("Zi.method()");
}
public static void show() {
System.out.println("Zi.show");
}
}
使用父类引用无法访问子类所特有的方法
解决方法向下转型:
向下转型(强制转换)
格式:<子类型> <引用变量名> = (<子类型> )<父类型的引用变量>;
特点:
父类转为子类,父类引用转为子类对象。理解为强制类型转换
在向下转型的过程中,如果没有转换为真实子类类型,会出现类型转换异常(java.lang.ClassCastException)
异常解决办法:Java提供了类型判断的语法: instanceof
格式:左边对象 instanceof 类名 这个表达式的结果是boolean类型测试它左边的对象是否是它右边的类的实例
有向下转型那自然有向上转型
向上转型(自动转换)
格式:<父类型> <引用变量名> = new <子类型>();
特点:
子类转为父类 父类的引用指向子类对象。理解为自动进行类型转换
此时通过父类引用变量调用的方法是子类覆盖或继承父类的方法
此时通过父类引用变量无法调用子类特有的属性和方法
public class DuoTaiDemo04 {
public static void main(String[] args) {
// Car c = new BMW();
// c.run();
// 想要访问BMW的fillOil,无法访问
// 利用向下转型
// BMW bmw = (BMW) c;
// bmw.fillOil();
//
// c = new Benz();
// c.run();
// Benz benz = (Benz) c;
// benz.leakOli();
// BMW bmw2 = (BMW) c;
// bmw2.fillOil();
// System.out.println(c instanceof BMW);
// System.out.println(c instanceof Benz);
Car c = new Benz();
c.run();
c = new BYD();
c.run();
if (c instanceof Benz) {
Benz benz = (Benz) c;
benz.leakOli();
} else if (c instanceof BMW) {
BMW b = (BMW) c;
b.fillOil();
} else if (c instanceof BYD) {
BYD byd = (BYD) c;
byd.electric();
}
Object obj = new BMW();
}
}
class Car {
public void run() {
System.out.println("Car.run()");
}
}
class BMW extends Car {
@Override
public void run() {
System.out.println("BMW.run()");
}
public void fillOil() {
System.out.println("加油");
}
}
class Benz extends Car {
@Override
public void run() {
System.out.println("Benz.run()");
}
public void leakOli() {
System.out.println("漏油");
}
}
class BYD extends Car {
@Override
public void run() {
System.out.println("BYD.run()");
}
public void electric() {
System.out.println("充电");
}
}
被abstract关键字所修饰的类被称为抽象类。
抽象类格式: abstract class 类名 {}
抽象类特点
不能被实例化
抽象类有构造方法,用来初始化父类继承的成员
抽象方法特点
抽象方法没有方法体
抽象方法必须在抽象类里
抽象方法必须在子类中被实现,除非子类是抽象类
注意事项
在类中没有方法体的方法,就是抽象方法。
含有抽象方法的类,即为抽象类。
抽象类不一定要包含抽象方法,若类中包含了抽象方法,则该类必须被定义为抽象类
如果一个子类没有实现抽象基类中所有的抽象方法,则子类也成为一个抽象类。
构造方法、静态方法、私有方法、final方法不能被声明为抽象的方法。
抽象类的成员一般使用 public 或者 protected
使用private ,final,static,native修饰抽象方法没有方法体,会有冲突,或没有意义。
抽象类和普通类的区别
抽象类中可以有成员变量,成员方法,构造方法,静态方法,常量 有的话又有什么意义呢
成员变量 --> 给子类使用
成员方法 --> 给子类使用
构造方法 --> 帮助子类初始化父类继承下来的成员
静态方法 --> 直接通过类名访问,防止创建对象的不建议访问方式
常量 --> 可以,方便访问
抽象类和普通类没有区别,只不过是抽象类多了抽象方法而已
抽象类的抽象方法强制子类重写
非抽象方法直接给子类使用
构造方法和成员变量直接给子类使用
抽象类是一个彻头彻尾的服务类,服务于所有的子类
public class AbstractDemo01 {
public static void main(String[] args) {
// Shape s2 = new Shape();
Shape s = new Triangle(2, 3, 4);
System.out.println(s.getPerimeter());
s = new Circle(1);
System.out.println(s.getPerimeter());
Shape.staticMethod();
System.out.println(Shape.NUM);
}
}
abstract class Shape {
public static int NUM = 100;
String name;
public Shape() {}
public Shape(String name) {
this.name = name;
}
public abstract double getPerimeter();
public abstract double getArea() ;
public void setName(String name) {
this.name = name;
}
public static void staticMethod() {
System.out.println("Shape.staticMethod()");
}
}
abstract class Square extends Shape {
}
class Rectangle extends Shape {
double width;
double length;
public Rectangle() {
super();
}
public Rectangle(String name, double width, double length) {
super(name);
this.width = width;
this.length = length;
}
@Override
public double getPerimeter() {
return (width + length) * 2;
}
@Override
public double getArea() {
// TODO Auto-generated method stub
return width * length;
}
}
class Triangle extends Shape {
double a;
double b;
double c;
public Triangle() {
super();
}
public Triangle(double a, double b, double c) {
super();
this.a = a;
this.b = b;
this.c = c;
}
public double getPerimeter() {
return a + b + c;
}
@Override
public double getArea() {
// TODO Auto-generated method stub
return 0;
}
}
class Circle extends Shape {
double r;
public Circle() {
super();
}
public Circle(double r) {
super();
this.r = r;
}
public double getPerimeter() {
return 2 * Math.PI * r;
}
@Override
public double getArea() {
// TODO Auto-generated method stub
return 0;
}
}
从本质上讲,接口是一种特殊的抽象类,这种抽象类中只包含常量和抽象方法的定义,而没有变量和方法的实现。
1.接口是一种标准,是一种规范,是一种约定
2.接口可以扩展功能
3.接口是灵活的,可以即插即拔
4.接口由继承者来实现
接口的格式:
格式
public interface 接口名{
//常量
//抽象方法
}
接口的实现类格式:
public 类名 implements 接口{
// 实现接口的方法
//普通方法
}
常量: 必须使用public static final修饰可省略。
方法:必须使用public abstract 修饰可省略。
1.接口使用interface修饰
2.接口是常量和抽象方法的集合
常量: 默认使用 public static final
方法: 默认使用 public abstract修饰
3.在JDK1.8以后不仅仅只有常量和抽象方法,还有默认方法和静态方法
默认方法用来直接给子类使用,如果子类想重写也可以自行根据需求重写,不会强制重写
静态方法用来直接通过接口名访问
4.接口不能够实例化
5.接口如果想要实例化--利用多态
6.接口的实现类特点:
如果一个类想要实现一个接口就必须实现接口中定义的所有抽象方法
如果一个类不想实现接口中的抽象方法,那么实现类也升级为接口
扩展类的功能
接口实现了多重继承,实现类和任何实现接口子类的通信和交互
接口更灵活,开发中常用
public class InterfaceDemo01 {
public static void main(String[] args) {
// System.out.println(Inter.num);
// Inter.num = 200;
// Inter.staticMethod();
// Inter inter = new Inter();
// 利用多态
Inter inter = new InterImpl();
}
}
interface Inter {
// int num = 100;
public static final int NUM = 100;
void show();
void method();
// 默认方法
public default void defaultMethod() {
System.out.println("Inter.defaultMethod()");
}
// 静态方法
public static void staticMethod() {
System.out.println("Inter.staticMethod()");
}
}
class InterImpl implements Inter {
@Override
public void show() {
System.out.println("InterImpl.show()");
}
@Override
public void method() {
System.out.println("InterImpl.method()");
}
}
interface InterSon extends Inter {
}