Java继承

957 阅读7分钟

一种类与类之间的关系

使用已存在的类的定义作为基础建立新类

新类的定义可以增加新的数据或新的功能,也可以用父类的功能,但不能选择性地继承父类

子类只能继承一个父类

package com.imooc.animal;
public class Animal {
	private String name;//昵称
	private int month;//月份
	private String species;//品种
	public Animal() {
		
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getMonth() {
		return month;
	}
	public void setMonth(int month) {
		this.month = month;
	}
	public String getSpecies() {
		return species;
	}
	public void setSpecies(String species) {
		this.species = species;
	}
	//吃东西
	public void eat() {
		System.out.print(this.getName()+"吃东西");
	}
}


package com.imooc.animal;
public class Cat extends Animal{
	private double weight;//体重
	public Cat() {
		
	}
	public double getWeight() {
		return weight;
	}
	public void setWeight(double weight) {
		this.weight = weight;
	}
	//跑动的方法
	public void run() {
		//子类可以访问父类非私有成员
		System.out.print(this.getName()+"是一只"+this.getSpecies()+",它在快乐地奔跑");
	}
}


package com.imooc.animal;
public class Dog extends Animal {
	private String sex; //性别
	public Dog() {
		
	}
	public String getSex() {
		return sex;
	}
	public void setSex(String sex) {
		this.sex = sex;
	}
	//睡觉的方法
	public void sleep() {
		System.out.println(this.getName()+"现在"+this.getMonth()+"月大"+",正在睡觉");
	}
        /*
	 * 方法重载:
	 * 1.同一个类中
	 * 2.方法名相同,参数列表不同(参数顺序、个数、类型)
	 * 3.方法返回值、访问修饰符任意
	 * 4.与方法的参数名无关
	
	private String sleep(String name) {
		return "";
	}
	public void sleep(String name,int month) {
		
	}
        public void sleep(int month,String name) {
		
	}
    * */
}


import com.imooc.animal.Animal;
import com.imooc.animal.Cat;
import com.imooc.animal.Dog;
public class Test {

	public static void main(String[] args) {
		Cat one=new Cat();
		one.setName("花花");
		one.setSpecies("中华田园猫");
		one.eat();
		one.run();
		Dog two=new Dog();
		two.setName("妞妞");
		two.setMonth(1);
		two.eat();
		two.sleep();
		//父类不可以访问子类特有成员,即便它是公有的
		Animal three=new Animal();
		//three.run();//报错
	}

}

方法重写

语法规则:

在子类中定义

方法名和参数类型、顺序、个数(不包括参数名)都要与父类继承的方法相同

        public void eat(String name) {
		System.out.println(name+"在吃东西");
	}
	public void jump() {
		System.out.println("跳跃是一种本能");
	}

        /*
	 * 方法重写:
	 * 1.有继承关系的子类中
	 * 2.方法名相同,参数列表相同(参数顺序、个数、类型)
	 * 3.与方法的参数名无关
	 * 4.方法的返回值和访问修饰符是可以允许有变化的
	 */
	//当子类重写父类方法后,子类对象调用的是重写后的方法
	public void eat() {
		System.out.println(this.getName()+"最近没有食欲");
	}
	public void eat(String month) {
		System.out.println(month+"最近没有食欲");
	}
	/*报错:与父类中的jump方法不兼容
	 * 返回值为void或者基本数据类型,要求父子完全一致
	 * 返回值为引用类型时,可以是父类或其子类
	public int jump() {
		System.out.println("狗狗是助跑式跳跃");
		return 1;
	}
	*/

在子类中可以定义与父类当中重名的属性,优先执行子类当中的赋值

访问修饰符

公有的:public:允许在任意位置访问

私有的:private:只允许在本类中进行访问

受保护的:protected:允许在当前类、同包子类/非子类、跨包子类调用;跨包非子类不允许

默认:允许在当前类、同包子类/非子类调用;跨包子类/非子类不允许调用

访问修饰符对方法重写的影响

访问修饰符的访问范围需要大于等于父类的访问范围

super关键字的使用

super:父类对象的引用

super.eat();
super.x=4;

tip:父类的构造方法不允许被继承、不允许被重写,但是会影响子类对象的实例化

子类的构造的过程中必须调用其父类的构造方法

如果子类的构造方法中没有显式标注,则系统默认调用父类无参构造方法

如果子类构造方法中既没有显式标注,且父类中没有无参的构造方法,则编译一定出错

Implicit super constructor Parent1() is undefined. Must explicitly invoke another constructor

隐式的父类无参构造方法未找到,必须显式地调用另外的构造方法

使用super()可以指定父类构造方法,super()必须放在子类构造方法有效代码第一行

super();

super(String name,int month);

this和super都不能在静态方法中调用,两者在调用构造方法时不能共存

继承后的初始化顺序

类的加载:父类静态成员--子类静态成员--子类对象实例化(父类对象构造,包括属性、构造代码块、构造方法--子类对象构造)

访问修饰符不影响静态成员加载顺序,跟书写位置有关

Object类

Object类是所有类的父类

一个类没有使用extends关键字明确标识继承关系,则默认继承Object类(包括数组)

Java中的每个类都可以使用Object中定义的方法

子类中方法可以不经过重写,直接重载父类的方法

例如equals()方法(等效于==),当继承Object中的equals方法时,比较的是两个引用是否指向同一个对象,即是否指向同一片内存空间,子类可以通过重写equals方法的形式,改变比较的内容

                Animal one=new Animal("花花",2);
		Animal two=new Animal("花花",2);
		boolean flag=one.equals(two);
		System.out.println("one 和   two的引用比较"+flag);
		System.out.println("one 和   two的引用比较"+(one==two));
		String str1=new String("hello");
		String str2=new String("hello");
		flag=str1.equals(str2);
		System.out.println("str1 和   str2的引用比较"+flag);
		System.out.println("str1 和   str2的引用比较"+(str1==str2));

         public boolean equals(Object obj) {
		 if(obj==null) {
			 return false;
		 }
		 //强制转换为Animal类型
		 Animal temp=(Animal)obj;
                 //字符串用equals()比较,int型数据用==比较
		 if(this.getName().equals(temp.getName())&&(this.getMonth()==temp.getMonth())) {
			 return true;
		 }else {
			 return false;
		 }
	 }

        //方法重载
	public boolean equals(Animal obj) {
		if(obj==null) {
			 return false;
		 }
		 if(this.getName().equals(obj.getName())&&(this.getMonth()==obj.getMonth())) {
			 return true;
		 }else {
			 return false;
		 }
	 }

if语句中,可以两个都用equals或者两个都用==进行比较吗?

由于通过Animal类型参数重载了equals(),所以代码运行时自动定位类型匹配方法

        //重写toString()方法
	public String toString() {
		return "昵称:"+this.getName()+";年龄:"+this.getMonth();
	}

                /*toString测试:
		 * 1.输出对象名时,默认会直接调用类中的toString方法
		 * 2.继承Object中的toString方法时,输出对象的字符串表示形式:类型信息+@+地址信息
		 * 3.子类可以通过重写toString方法的形式,改变输出的内容以及表现形式
		 */
		System.out.println(one.toString());
		System.out.println(one);
		System.out.println(str1);

==比较的是变量里存储的值,对于基本数据类型,变量里存储的是数值,==比较的是数值是否相等;对于引用数据类型(例如String、自定义类等),变量里存的是对象的内存地址,==默认比较的是是否指向同一内存空间,也就是地址是否相同。

final

final class:该类没有子类,不允许被继承 可写成public final class或final public class

不允许子类重写,在方法的返回值前加final,同时可以被子类正常继承使用,不能修饰构造方法

变量分为以下两类:

final 方法内局部变量:只要在具体被使用之前进行赋值即可,一旦赋值不允许被修改

final 类当中的成员属性:赋值过程:1.定义直接初始化 2.构造方法 3. 构造代码块

不赋值系统会报错

提示菜单快捷键:alt+/ 可以快速生成重写方法模板

final 引用数据类型 实例化后不允许再进行引用地址的修订,但属性值仍可更改

static+final 表示全局不允许修订的内容(方法和变量),如配置信息

注解

可以声明在包、类、属性、方法、局部变量、方法参数等的前面,用来对这些元素进行说明、注释

按照运行机制可以分为:源码注解(@Override)、编译时注解(@NotNull)、运行时注解(甚至会影响到运行逻辑@Autowired)

在当前阶段保留,在进行下一阶段时会被丢弃

按照来源分:来自JDK的注解(@Override)、来自第三方的注解(@Autowired)、我们自己定义的注解

元注解

定义注解的注解,对注解进行标注

父类的静态方法无法被重写

public static Animal create(){
    return new Animal();
}

public static Dog create(){
    return new Dog();
}

不会报错的原因是:系统认为create是Dog类专属的一个方法,与父类无关,更不是方法重写