Java基础-Lesson8多态

1、super关键字

super  关键字的作用,访问父类成员

        super.属性名  //访问父类属性

        super.方法名()  //访问父类方法

        super(参数列表)  //访问父类的构造方法

(1)用super调用父类的构造方法

要构造子类,必须先构造父类  //要执行子类的构造方法,必须先执行父类的构造方法

class Parent{
}

class Son extends Parent{
}

实际上,这段代码会被处理成:

//如果不声明继承谁,就相当于继承自Object
class Parent extends Object{
	//如果我们不提供构造方法,系统会帮我们生成一个默认的
	public Parent() {
		//如果我们不显示的调用父类的构造方法,系统会帮我们调用
		super();
	}
}
class Son extends Parent{
	public Son() {
		super();
	}
}

由以上知识点可以作为一个考察点,比如

class Parent{
	public Parent(String name) {
		
	}
}
class Son extends Parent{
	public Son() {
		super();  //报错
	}
}
//又或是以下这种写法
class Son extends Parent{  //报错
	
}

这是因为当子类调用super()时试图调用父类的无参构造方法,或不调用时系统默认的调用父类的无参构造方法,这两种情况都会编译出错,因为父类没有无参的构造方法,要想修正  

方法一:给父类加一个无参的构造方法

方法二:明确的在子类的构造方法中,用super(参数)的方式指明调用父类的某个构造方法              

class Parent{
	public Parent(String name) {
		
	}
}
class Son extends Parent{  //报错
	public Son() {
		super("张三");
	}
}

 (2)super()必须放在子类构造方法的第一行

比如

class Machine{
	String productor;
	String name;
	Machine(String productor,String name){
		this.productor=productor;
		this.name=name;
	}
}
class Computer extends Machine{
	String cpu;
	int disk;
	Computer(String productor,String name,String cpu,int disk){
		super(productor,name);  //调用父类的构造方法
		this.cpu=cpu;
		this.disk=disk;
	}
}

(3)为什么this()和super()在子类的同一个构造方法中不能同时存在

因为this()必然引起本类中其他的构造方法的执行,这个其他的构造方法的第一句,也必然是super(...)

(4)为什么this()这个动作,必须放在构造方法的第一行

因为this()这个动作会调用本类的其他构造方法,其他构造方法第一句必然是super(),由于super()需要放在第一句,所以this()也需要放在构造方法的第一句,比如

class Machine{
	String productor;
	String name;
	Machine(String productor,String name){
		this.productor=productor;
		this.name=name;
	}
}
class Computer extends Machine{
	String cpu;
	int disk;
	Computer(String productor,String name,String cpu,int disk){
//		super(productor,name);  //this()和super()不能同时出现在一个构造方法里
		this(productor,name,cpu);  //必须放在第一行
		this.disk=disk;
	}
	Computer(String productor,String name,String cpu){
		super(productor,name);
		this.cpu=cpu;
	}
}

2、重写和多态

重写:override  发生在父子类之间  方法的签名相同(方法名,参数个数和类型,返回值类型)

重载:overload  发生在同一个类中  方法名相同,参数个数和类型有所不同,不关心返回值

多态:主要体现在,在定义方法参数的时候,用基类定义传参的时候可以传入这个基类的子类,运行的时候,表现出来的是不同的子类的行为,这就称为多态,比如

public class Test3 {

	public static void main(String[] args) {
		Student stu = new Student();
		talk(stu);
		PrimarySchoolStudent psstu = new PrimarySchoolStudent();
		//或写成Student psstu = new PrimarySchoolStudent();用基类的引用指向子类对象
		talk(psstu);
		UniversityStudent ustu = new UniversityStudent();
		//或写成Student ustu = new UniversityStudent();用基类的引用指向子类对象
		talk(ustu);
		/**
		 *  输出为:
		 *  和学生交谈
			我是学生
			和学生再见
			和学生交谈
			我是小学生
			和学生再见
			和学生交谈
			我是大学生
			和学生再见
		 */
	}
	static void talk(Student student) {
		System.out.println("和学生交谈");
		student.say();
		System.out.println("和学生再见");
	}
}
class Student{
	void say() {
		System.out.println("我是学生");
	}
}
class PrimarySchoolStudent extends Student{
	void say() {
		System.out.println("我是小学生");
	}
}
class UniversityStudent extends Student{
	void say() {
		System.out.println("我是大学生");
	}
}

多态的好处:

①提高了方法的可重用性,程序更精简

②提高了方法的向后兼容性

3、对象的类型转换

public class Test3 {

	public static void main(String[] args) {
		Student stu = new Student();
		talk(stu);
		PrimarySchoolStudent psstu = new PrimarySchoolStudent();
		//或写成Student psstu = new PrimarySchoolStudent();用基类的引用指向子类对象
		talk(psstu);
		UniversityStudent ustu = new UniversityStudent();
		//或写成Student ustu = new UniversityStudent();用基类的引用指向子类对象
		talk(ustu);
        /**
		 *  输出为:
		 *  ================
            我是学生
            ================
            我是小学生
            ================
            我是大学生
            学习数据库
		 */
	}
	static void talk(Student student) {
		System.out.println("================");
		student.say();
		if(student instanceof UniversityStudent) {
			((UniversityStudent)student).study();
		}
	}
}
class Student{
	void say() {
		System.out.println("我是学生");
	}
}
class PrimarySchoolStudent extends Student{
	void say() {
		System.out.println("我是小学生");
	}
}
class UniversityStudent extends Student{
	void say() {
		System.out.println("我是大学生");
	}
	void study() {
		System.out.println("学习数据库");
	}
}

注意:对象的类型转换,要求必须是本类的示例才能转换,否则会出现ClassCastException异常

4、Object类

是Java类中最顶层的类,所有的类都是从它继承来的

它提供了几个常用的方法

hashCode()  //取对象的哈希值

wait()  //用于线程通讯

notify()  //用于线程通讯

notifyAll()  //用于线程通讯

toString()  //把对象转成字符串,直接打印对象的时候会自动调用这个方法

equals()  //比较对另一个对象和“我”(调用equals()方的对象)是不是相等

finalize()  //对象被垃圾回收器回收的时候会自动调用这个方法

clone()  //克隆

getClass()  //得到Class对象

public class Test5 {
	public static void main(String[] args) {
		Cat cat = new Cat(2,"TOM");
		System.out.println(cat.toString());  //Cat [age=2, name=TOM]
	}
}
class Cat{
	int age;
	String name;
	public Cat(int age, String name) {
		super();
		this.age = age;
		this.name = name;
	}
	@Override
	public String toString() {
		return "Cat [age=" + age + ", name=" + name + "]";
	}
}

一个需要记住的知识点

public class Test4 {
	public static void main(String [] args) {
		int x1 = 2147483647+1;
		System.out.println(x1);  //-2147483648
		long x2 = 2147483647+1;
		System.out.println(x2);  //-2147483648
		long x3 = 2147483647+1L;
		System.out.println(x3);  //2147483648
	}
}

5、抽象类

用abstract修饰的类

抽象方法:用abstract修饰,只有声明,没有实现,实现交给子类重写,含有抽象方法的类,必须声明为抽象类

抽象类的特点:

①用abstract修饰

②不能new出来,只能new它的子类,这个子类如果不能完全实现抽象类中的全部抽象方法,则它还是一个抽象类

③抽象类除了有抽象方法之外,其他的和普通类完全相同

比如

public class Test6 {
	public static void main(String[] args) {
		Bank bank = new ABCBank();
		bank.save();  //银行存钱
		bank.take();  //银行取钱
	}
}
abstract class Bank{
	abstract void save();
	abstract void take();
}
class ABCBank extends Bank{
	void save() {
		System.out.println("银行存钱");
	}
	void take() {
		System.out.println("银行取钱");
	}
}

6、接口

接口可以理解为一种特殊的抽象类

如果抽象类中的所有的方法都是抽象的,可以用接口来代替

接口的特点:

①接口也不能new,要new它的实现类

②接口中所有的方法都是public 的

        小常识:方法在子类中重写的时候,它的访问级别不能低于父类

        public  protected  default  private

public class TestInterface {
	public static void main(String[] args) {
		Bank bank = new ABCBank();
		bank.save();
		bank.take();
	}
}
interface Bank{
	void save();
	void take();
}
class ABCBank implements Bank{
	public void save() {  //如果不加public就会报Cannot reduce the visibility of the inherited method 
		System.out.println("银行存钱");
	}
	public void take() {
		System.out.println("银行取钱");
	}
}

③接口可以继承接口,甚至可以多继承

interface A{
	
}
interface B{
	
}
interface C extends A,B{
	
}

④接口中的所有属性都相当于public static final 的,接口其实相当于抽象方法和常量的集合

public class TestInterface {
	public static void main(String[] args) {
		Bank.total();
	}
}
interface Bank{
	void save();
	void take();
	static void total() {
		System.out.println("总额是....");
	}
}

⑤jdk1.8 以后接口中可以有静态方法,默认方法(而且可以重写)

⑥一个类可以在继承一个类的同时,实现一或多个接口

⑦接口可以设计成空接口,JDK中就有这样的接口,称为标记接口,比如Serializeable  Cloneable等

⑧接口可以声明在类内部作为内部接口,可以使用public  private  protected修饰,但能修饰外部接口的修饰符只有public

class T{
	interface A{};  //可以使用public private protected修饰符
}

7、final关键字

用来修饰 类,属性,方法,局部变量,方法参数

(1)用final修饰的类不能被继承,jdk中就有这样的类,比如 tring  System  Math

(2)用final修饰的方法不能被重写

(3)用final修饰的属性在定义的同时就要初始化,如果不在定义的时候初始化则要在构造方法中初始化,如果有多个构造方法则要在每个构造方法中都进行初始化

(4)用final修饰的静态属性,必须在定义的同时进行初始化

(5)用final修饰的局部变量要在使用之前初始化

(6)用final修饰的引用,这个引用(地址)不能变但是引用指向的内容是可变的

public class TestFinal {
	public static void main(String[] args) {
		Sheep sheep = new Sheep();
		test(sheep);
		System.out.println(sheep.age);  //1
	}
	static void test(final Sheep sheep) {
		//sheep=null;  //编译错误
		sheep.age++;
	}
}
class Sheep{
	int age;
}

8、对象的比较

“==” 比的就是变量的字面量本身,比如

public class TestCompare {
	public static void main(String[] args) {
		Dog d1 = new Dog(2,"tom");
		Dog d2 = new Dog(2,"tom");
		System.out.println(d1==d2);  //false
		System.out.println(d1.equals(d2));  //false
	}
}
class Dog{
	int age;
	String name;
	public Dog(int age, String name) {
		super();
		this.age = age;
		this.name = name;
	}
}

对于上面的程序,因为我们没有重写equals方法,它是从Object类继承来的,所以比较的结果也是false,下面是Object类中equals的源码

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

如果想按照自己的想法实现对象的比较就要重写equals方法,比如

public class TestCompare {
	public static void main(String[] args) {
		Dog d1 = new Dog(2,"tom");
		Dog d2 = new Dog(2,"tom");
		System.out.println(d1==d2);  //false
		System.out.println(d1.equals(d2));  //true
	}
}
class Dog{
	int age;
	String name;
	public Dog(int age, String name) {
		super();
		this.age = age;
		this.name = name;
	}
	public boolean equals(Object obj) {
		if(this==obj)return true;
		if(!(obj instanceof Dog))return false;
		Dog dog = (Dog)obj;
		if(this.age==dog.age&&this.name==dog.name)return true;
		else return false;
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值