Final
1.是什么
final 是修饰符,表示最终的,无法修改的
2.能做什么
- 修饰的变量不能二次赋值,一般叫常量(但是常量一般是psf的 public static final)
- 修饰的成员方法不能被覆写
- 修饰的类不能被继承
3.怎么用
//final int b=0;
final int b;
{
b=1;
}
final static int c;
static {
c=2;
}
class A {
public final void m1(){
}
}
class B extends A{
//m1被final修饰无法覆写
// @Override
// public void m1(){}
public void m2(){}
}
final class Sup{
}
//被final修饰的类也无法被继承
//class Sub extends Sup{
//}
4.修饰引用类型
final Customer customer=new Customer(18);
//age属性没有被final修饰,所以可以被二次赋值
customer.age=20;
System.out.println(customer.age);
//customer被final修饰无法二次赋值
//customer=new Customer(12);
class Customer{
int age;
Customer(int age) {
this.age=age;
}
}
多态
1.是什么
JVM四大特性:多线程、跨平台、自动垃圾回收、面向对象
面向对象特性:封装、继承、多态、抽象
多态:多态性,多形态,统一操作用于不同对象可以有不同的解释,产生不同的结果
父类引用指向子类对象 : 通过父类创建的引用类型变量,可以找到子类的对象
父类 变量名=new 子类();
能够使用父类的地方就一定可以使用子类(里氏替换原则)
2.相关知识
单一职责原则:
里氏替换原则:能够使用父类的地方就一定可以使用子类
依赖倒置原则:面向高层编程,底层应该依赖高层,而高层不依赖底层
接口隔离原则
迪米特法则
开闭原则
3.应用场景
多态应用场景
当一个需求对应多种不同实现的时候一定要使用多态
当一个需求只有一种实现的时候不需要使用多态
public static void main(String[] args) {
User user=new User();
user.test(new Cat());
//Cat cat=new Cat();与上一行代码相同
//user.test(cat);
user.test(new Dog());
class User {
public void test(Animal animal){
animal.eat();
}
}
abstract class Animal{
public abstract void eat();
}
class Cat extends Animal{
@Override
public void eat() {
System.out.println("猫吃鱼");
}
}
class Dog extends Animal{
@Override
public void eat() {
System.out.println("狗吃肉");
}
}
}
4.优点
提高程序灵活性,扩展性,维护性,符合高内聚低耦合理念
5.缺点
丢失子类特有的属性(父类没有的,子类有,都属于子类特有,无法访问)
6.使用语法
通过多态进行调用:
- 父类没有的,都调用不了
- 父类有的,子类没有的,都执行父类
- 父类有,子类也有,除了成员方法执行子类,其他的都执行父类
Sup1 s1=new Sub1();
//父类有则可以调用
System.out.println(s1.a);
System.out.println(s1.b);
System.out.println(s1.c);
//父类中没有所以报错,不能调用
//System.out.println(s1.d);
//父类
s1.m1();
//子类 中只有成员方法执行,其他的都执行父类的
s1.m2();
class Sup1{
int a =1;
static int b =2;
int c=3;//父类特有
public static void m1(){
System.out.println("父类静态");
}
public void m2(){
System.out.println("父类成员");
}
}
class Sub1 extends Sup1{
int a=11;
static int b=22;
int d=4;
public static void m1(){
System.out.println("子类静态");
}
public void m2(){
System.out.println("子类成员");
}
}
7.Instanceof
多态发生在赋值的时候,不赋值不会发生多态
多态:又叫向上转型,子到父,类似自动类型转换
向下转型:父到子,类似强制类型转换
必须先向上转型,才能发生向下转型,父类转型不可能小于子类
//向上转型
Sup2 s=new Sub2();
//向下转型
Sub2 s3=(Sub2)s;
Sup2 s4=new Sup2();
// 下面运行会报错,因为没有发生向上转型,当强制转型为子类时,会出现错误
// java.lang.ClassCastException: Day11(包名).Sup2 cannot be cast to Day11.Sub2
// 类型转换异常
// Sub2 sb2 = (Sub2) s4;
// 判断某个对象是否由某个类实例化而来
// 当true的时候,在进行向下转型,就可以避免类型转换异常
System.out.println(s4 instanceof Sub2);
8.多态的几种形式
//1.直接多态 父类 变量=new 子类();
Sup2 s2=new Sub2();
//2.形参实参多态 参数列表用父类声明,调用方法时传入子类对象
m21(new Sub2());
//3.返回值多态 返回值类型为父类类型 但是返回的值是子类对象
Sup2 i = m22();
public static Sup2 m22(){
return new Sub2();
}
public static void m21(Sup2 s){
}
简单来说:只要是父类的引用类型变量保存的子类的对象就是多态
9.隐式多态
public class Poly_05 {
public static void main(String[] args) {
// SupClass sup = new SubClass();
// System.out.println(sup.i);
// sup.m2();
SubClass sub = new SubClass();
// System.out.println(sub.i);
sub.m1();
// sub.m2();
// System.out.println(sub + "===");
}
}
class SupClass {
int i = 2;
public void m1() {
// System.out.println(this + "--------");
// 这里的 this 会发生多态
/**
* this 是当前对象中第一个成员变量,用于保存当前类对象的内存地址
*
* 所以 this的类型可以为 当前类类型 或 父类类型 , 如果是父类类型,就是多态
*
* 多态 丢失子类特有的属性
*
* 但是this可以调用特有属性,所以 this的类型应该是 当前类类型 , 也就是 SupClass
*
* SupClass this ;
*
* this 出现在成员方法和构造方法中的时候, 谁调用的这个方法,this就指向谁
*
* 由于是子类对象调用的m1,所以 this指向的是子类对象的内存地址
*
* 得知 SupClass this = 子类对象;
*/
System.out.println(this.i);
this.m2();
}
public void m2() {
System.out.println("父类m2");
}
}
class SubClass extends SupClass {
int i = 22;
public void m2() {
System.out.println("子类m2");
}
}
通过子类调用(未经覆写)父类的方法时,父类方法中的上下文环境就是多态环境
abstract
1.是什么
abstract 是修饰符,表示抽象
修饰的成员方法是抽象方法,并且没有方法体{}
修饰的类是抽象类,该种类不能创建对象
抽象方法必须在抽象类中,用于被子类覆写(或实现)
抽象类中可以没有抽象方法
abstract和final不能同时出现
如果一个类继承了一个抽象类,需要实现抽象类的所有的抽象方法
一个抽象类继承一个抽象类需要实现0~N个抽象方法,即可以一个也不实现
2.使用语法
//抽象类
abstract class C{
{
}
static{
}
//普通类能写的抽象类也能写,只是可以额外写抽象方法
//抽象类虽然不能创建对象,但是有构造方法,用于让子类创建对象是调用(构造方法第一行默认有super())
//抽象方法
public abstract void m11();
//成员方法
public void m12(){
}
//构造方法
public C(){}
//静态方法
public static void m13(){}
}
class D extends C{
@Override
public void m11() {
}
}
//抽象类继承抽象类,可以实现0~N个抽象方法
abstract class E extends C{
}
3.应用场景
class Animal{
public void eat(){
System.out.println("动物吃东西");
}
}
这里放在动物类中,只是规定了动物吃东西的功能,但是无法确定到底吃什么
class Cat extends Animal{
@Override
public void eat() {
System.out.println("猫吃鱼");
}
}
class Dog extends Animal{
@Override
public void eat() {
System.out.println("狗吃肉");
}
}
看到某个具体动物的时候我们才知道他吃什么
所以引入Animal类的目的是降低耦合度,又因为多态会丢失子类特有的属性,所以要在Animal类中添加动物吃东西的功能,然后又子类去覆写实现该功能,最后通过多态进行调用时,依然会执行子类覆写之后的方法
由此可见,Animal类只是进行功能定义,但是不包括功能实现,此时该方法应该定义为抽象方法,可以提醒子类进行覆写方法
abstract class Animal{
public abstract void eat();
}