Java语言基础 10:final 关键字、多态、多态的好处和弊端、对象间的转型问题(向下转型和向上转型)、多态中内存结构图解、多态的代码练习、


1、final 关键字

(1)final 关键字是“最终的意思”,可以修饰类、修饰成员变量、修饰成员方法。

        final 修饰类:最终类,该类不能被继承。

        final 修饰成员方法:最终成员方法,该成员方法不能被子类重写。

        final 修饰成员变量:该成员变量不能被重新赋值。它就变成了常量,只能被赋值一次。

A:字面值常量    String str="abc" ;    B:自定义常量    final int num=100 ;

(2)final 关键字修饰局部变量。

final  修饰基本数据类型的变量,基本类型的值不能改变。

final  修饰引用数据类型的变量,引用类型的地址值不能改变,但是,该对象 堆内存的值 是可以改变的。

(3)final 关键字修饰变量的初始化时机。

        1)被final 修饰的变量只能被赋值一次。

        2)在构造方法完毕前被初始化(这是针对非静态的常量)。

2、多态的概念

(1)多态:同一个对象在不同时刻体现出来的不同状态。

(2)多态的前提:

        A:要有继承关系。

其实没有也是可以的,但是没有这个就没有意义了。

        C:要有父类引用指向子类对象。父类名 f = new 子类名();

(3)多态中的成员访问特点

A:成员变量:编译看左边,运行看左边。

B:构造方法:创建子类对象的时候,访问父类的构造方法,对父类的数据进行初始化。

C:成员方法:编译看左边,运行看右边。(由于成员方法存在重写,所以它运行看右边)

D:静态方法:编译看左边,运行看左边。(静态和类相关,算不上重写,所以访问的还是父类的)


3、多态的好处和弊端

(1)提高了代码的维护性(继承来保证)。

(2)提高了代码的扩展性。

多态的弊端:只能使用父类的功能,不能使用子类的特有功能。

如果就想使用,该怎么办呢?解决办法如下:

        A:创建子类对象去调用方法即可。可以,但是不合理,太占用内存。

        B:把父类的引用强制转换为子类的引用(向下转型)。

对象间的转型问题:

A:向上转型:子类对象赋值给父类引用。Fu f  = new Zi ( ) ;

B:向下转型:父类引用赋值给子类对象。Zi z = (Zi)f ;    前提:要求该f 必须能够转换为Zi 的。

java ldap 改口令 javalibrary口令_方法重写

4、多态继承中的内存图解

java ldap 改口令 javalibrary口令_方法重写_02

5、多态中的对象变化内存图解

java ldap 改口令 javalibrary口令_多态_03

ClassCastException:类的转换异常,通常在类的向下转型中出现!

6、多态练习

/*
	多态练习:猫狗案例
*/
class Animal {
	public void eat(){
		System.out.println("吃饭");
	}
}

class Dog extends Animal {
	public void eat() {
		System.out.println("狗吃肉");
	}
	
	public void lookDoor() {
		System.out.println("狗看门");
	}
}

class Cat extends Animal {
	public void eat() {
		System.out.println("猫吃鱼");
	}
	
	public void playGame() {
		System.out.println("猫捉迷藏");
	}
}

class DuoTaiTest {
	public static void main(String[] args) {
		//定义为狗
		Animal a = new Dog();
		a.eat();
		System.out.println("--------------");
		//还原成狗
		Dog d = (Dog)a;
		d.eat();
		d.lookDoor();
		System.out.println("--------------");
		//变成猫
		a = new Cat();
		a.eat();
		System.out.println("--------------");
		//还原成猫
		Cat c = (Cat)a;
		c.eat();
		c.playGame();
		System.out.println("--------------");
		
		//演示错误的内容
		//Dog dd = new Animal();	//编译时错误
		//Dog ddd = new Cat();		//编译时错误
		//ClassCastException:		
		//Dog dd = (Dog)a;			//运行时错误
	}
}
/*
	不同地方饮食文化不同的案例
*/
class Person {
	public void eat() {
		System.out.println("吃饭");
	}
}

class SouthPerson extends Person {
	public void eat() {
		System.out.println("炒菜,吃米饭");
	}
	
	public void jingShang() {
		System.out.println("经商");
	}
}

class NorthPerson extends Person {
	public void eat() {
		System.out.println("炖菜,吃馒头");
	}
	
	public void yanJiu() {
		System.out.println("研究");
	}
}

class DuoTaiTest2 {
	public static void main(String[] args) {
		//测试
		//南方人
		Person p = new SouthPerson();
		p.eat();
		System.out.println("-------------");
		SouthPerson sp = (SouthPerson)p;
		sp.eat();
		sp.jingShang();
		System.out.println("-------------");
		
		//北方人
		p = new NorthPerson();
		p.eat();
		System.out.println("-------------");
		NorthPerson np = (NorthPerson)p;
		np.eat();
		np.yanJiu();
	}
}



/*
    看程序写结果:先判断有没有问题,如果没有,写出结果
    
    多态的成员访问特点:
        方法:编译看左边,运行看右边。
        
    继承的时候:
        子类中有和父类中一样的方法,叫重写。
        子类中没有父亲中出现过的方法,方法就被继承过来了。
*/
//    爱你
class A {
    public void show() {
        show2();
    }
    public void show2() {
        System.out.println("我");
    }
}
class B extends A {
    /*
    public void show() {
        show2();
    }
    */

    public void show2() {
        System.out.println("爱");
    }
}
class C extends B {
    public void show() {
        super.show();
    }
    public void show2() {
        System.out.println("你");
    }
}
public class DuoTaiTest4 {
    public static void main(String[] args) {
        A a = new B();
        a.show();
        
        B b = new C();
        b.show();
    }
}




7、抽象类:abstract class Animal { }

(1)一个没有方法体的方法 应该定义为 抽象方法,而类中如果有抽象方法,该类必须定义为抽象类。

抽象类中可以没有抽象方法。

空方法体:写了空的大括号 { }        public abstract void eat() { }     //报错

没有方法体:不写大括号 { }             public abstract void eat() ;

(2)抽象类的特点:

关键字 修饰。

        2)抽象类中不一定有抽象方法,但是有抽象方法的类 必须定义为抽象类。

另:抽象类的实例化其实是靠具体的子类实现的,是多态的方式!

        4)抽象类有构造方法,但是不能实例化,构造方法用于子类访问父类数据的初始化。

(3)抽象类的子类:

        1)如果不想重写抽象父类的抽象方法,这时,抽象类的子类是一个抽象类。

        2)重写了抽象父类的所有抽象方法,这时,子类是一个具体的类。

(4)抽象类的成员特点:

        1)成员变量:可以是变量,也可以是常量。

        2)构造方法:有,用于子类访问父类数据的初始化。

        3)成员方法:可以是抽象方法,也可以是非抽象方法。

抽象类的成员方法特性:

1)抽象方法:强制要求子类要做的事情。

2)非抽象方法:子类继承的事情,提高代码复用性。

8、抽象类和多态的举例

//定义抽象的动物类
abstract class Animal {
	//姓名
	private String name;
	//年龄
	private int age;
	
	public Animal() {}
	
	public Animal(String name,int age) {
		this.name = name;
		this.age = age;
	}
	
	public String getName() {
		return name;
	}
	
	public void setName(String name) {
		this.name = name;
	}
	
	public int getAge() {
		return age;
	}
	
	public void setAge(int age) {
		this.age = age;
	}
	
	//定义一个抽象方法
	public abstract void eat();
}

//定义具体的狗类
class Dog extends Animal {
	public Dog() {}
	
	public Dog(String name,int age) {
		super(name,age);
	}
	
	public void eat() {
		System.out.println("狗吃肉");
	}
}

//定义具体的猫类
class Cat extends Animal {
	public Cat() {}
	
	public Cat(String name,int age) {
		super(name,age);
	}
	
	public void eat() {
		System.out.println("猫吃鱼");
	}
}

//测试类
class AbstractTest {
	public static void main(String[] args) {
		//测试狗类
		//具体类用法
		//方式1:
		Dog d = new Dog();
		d.setName("旺财");
		d.setAge(3);
		System.out.println(d.getName()+"---"+d.getAge());
		d.eat();
		//方式2:
		Dog d2 = new Dog("旺财",3);
		System.out.println(d2.getName()+"---"+d2.getAge());
		d2.eat();
		System.out.println("---------------------------");
		
		Animal a = new Dog();
		a.setName("旺财");
		a.setAge(3);
		System.out.println(a.getName()+"---"+a.getAge());
		a.eat();
		
		Animal a2 = new Dog("旺财",3);
		System.out.println(a2.getName()+"---"+a2.getAge());
		a2.eat();
		
		//练习:测试猫类
	}
}



/*
	学生案例
		具体事务:基础班学员,就业班学员
		共性:姓名,年龄,班级,学习,吃饭
	分析:
		基础班学员
			成员变量:姓名,年龄,班级
			成员方法:学习,吃饭
		就业班学员
			成员变量:姓名,年龄,班级
			成员方法:学习,吃饭
			
		得到一个学员类。
			成员变量:姓名,年龄,班级
			成员方法:学习,吃饭			
	实现:
		学员类
		基础班学员
		就业班学员
*/
//定义抽象学员类
abstract class Student {
	//姓名
	private String name;
	//年龄
	private int age;
	//班级
	private String grand;
	
	public Student() {}
	
	public Student(String name,int age,String grand) {
		this.name = name;
		this.age = age;
		this.grand = grand;
	}
	
	public String getName() {
		return name;
	}
	
	public void setName(String name) {
		this.name = name;
	}
	
	public int getAge() {
		return age;
	}
	
	public void setAge(int age) {
		this.age = age;
	}
	
	public String getGrand() {
		return grand;
	}
	
	public void setGrand(String grand) {
		this.grand = grand;
	}
	
	//学习
	public abstract void study();
	
	//吃饭
	public void eat() {
		System.out.println("学习累了,就该吃饭");
	}
}

//具体基础班学员类
class BasicStudent extends Student {
	public BasicStudent() {}
	
	public BasicStudent(String name,int age,String grand) {
		super(name,age,grand);
	}
	
	public void study() {
		System.out.println("基础班学员学习的是JavaSE");
	}
}

//具体就业班学员类
class WorkStudent extends Student {
	public WorkStudent() {}
	
	public WorkStudent(String name,int age,String grand) {
		super(name,age,grand);
	}
	
	public void study() {
		System.out.println("就业班学员学习的是JavaEE");
	}
}

class AbstractTest3 {
	public static void main(String[] args) {
		//我仅仅测试基础班学员
		//按照多态的方式测试
		Student s = new BasicStudent();
		s.setName("林青霞");
		s.setAge(27);
		s.setGrand("1111");
		System.out.println(s.getName()+"---"+s.getAge()+"---"+s.getGrand());
		s.study();
		s.eat();
		System.out.println("--------------");
		
		s = new BasicStudent("武",48,"1111");
		System.out.println(s.getName()+"---"+s.getAge()+"---"+s.getGrand());
		s.study();
		s.eat();
		
		//就业班测试留给自己玩
	}
}



9、抽象类的小问题:

(1)一个类如果没有抽象方法,可以被定义为抽象类吗?

答:可以。这样做的意义是:不让去创建对象,只能使用它的子类去访问。

(2)abstract 关键字不能和哪些关键字共存?

1)private :私有的是不能被继承的,更别提被子类重写了,而抽象是要求必须被子类重写的,所以出现了冲突。

2)final :final 是最终的,不能被子类重写,而抽象是要求必须被子类重写的,所以出现了冲突。

3)static :无意义:abstract 方法是没有方法体的,而static 方法是可以直接被类名调用的,通过类名去调用一个没有方法体的方法意义何在,所以无意义。