继承小例子

class Human {
	public String name = "小黄"; // 姓名
	public int age = 22; // 年龄
}
class Student extends Human {
	public double score = 66.6; // 分数
}
class Graduate extends Student {
	public String mentor = "小勇"; // 导师
}
public class TestExtends {
	public static void main(String[] args) {
		Graduate gd = new Graduate();
		System.out.printf("%s %d %f %s\n", gd.name, gd.age, gd.score, gd.mentor);
	}
}

继承

  • 一个新类从已有的类那里获得其已有的属性和方法,这种现象叫类的继承
  • 这个新类被称为子类,也叫派生类,已有的那个类叫做父类,也叫做基类
  • 继承的好处
  1. 代码得到极大的重用
  2. 形成一种类的层次体系结构
  3. 为多肽创造条件
  • 继承的实现方式
  • class SubClass extends SuperClass {}

java类的继承实验 java继承类例子_继承的原则

  • Java只支持单继承,不允许多重继承
  • 单继承就是一个类只能有一个父类
  • 多继承就是一个类可以有多个父类
  • 可以有多层继承,即一个类可以继承某一个类的子类,如类B继承了类A,类C又可以继承类B,那么类C也间接继承了类A。
  • 子类可以继承父类所有的成员变量和成员方法,但子类永远无法继承父类的构造方法。在子类的构造方法中可使用语句super(参数列表)调用父类的构造方法。

继承的访问控制权限

同包继承权限问题(重点)
  • 子类的所有方法内部都可以访问父类除私有成员以外的所有成员,所谓子类的所有方法也包括子类的私有方法
  • 通过子类对象名可以访问
  1. 父类除私有成员外的所有成员
  2. 子类本身的除私有成员外的所有成员
  3. 附注:私有成员包括私有属性和私有方法
  • 子类可以继承父类除私有成员以外的所有成员
  • 父类的私有成员不可以被子类继承,其他的成员都可以被子类继承
  • 不同包之间的继承问题,后面还会讨论
// 说明了:子类内部可以访问父类非私有的成员,私有成员无法被子类方法访问
//        通过子类对象名只能访问从父类继承过来的非私有成员
//   总结:私有不能被继承
//         私有物理上已经被继承过来了,只不过逻辑上程序员不能去访问它
//         因此继承必须慎重,否则会浪费内存
class A {
	public int i;
	protected int j;
	private int k;

	public void g() {
	}
	private void s() {
	}
	protected void b() {}
}
class B extends A {
	private void g() {
		i = 10;
		j = 20;
		// k = 30; // error 私有属性不能被继承
		g();
		b();
		// s(); // error 私有方法不能被继承
	}
	public void f() {
		i = 10;
		j = 20;
		// k = 30; // error 私有属性不能被继承
		g();
		b();
		// s(); // error 私有方法不能被继承
	}
}
class M {
	public static void main(String[] args) {
		B bb = new B();
		bb.i = 20;
		bb.j = 30;
		bb.b();
		bb.g();

		// bb.s(); // error
		// bb.k = 22; // error
	}
}

继承的原则

  • 何时选择继承?
  • 一个很好的经验:“B是一个A吗?”
  • 如果是则让B做A的子类
  • 注意:经常犯的错误,A有一个B吗?例如让汽车轮子成为汽车的子类是错误的

不同访问修饰符

public

protected

default

private

同包同类





访问同包不同类




同包不同类继承




不同包继承



访问不同包无任何关系的类


super关键字

class A {
	public int i;
	public int j;
}
class B extends A {
	public int k;
	public B() {}
	public B(int i, int j, int k) {
		this.i = i; // 一定要明白为什么i前面可以加this
		this.j = j; // 因为i是通过A继承过来的,所以B里面也有i,所以可以加this
		this.k = k;
	}
}
public class TestSuper {
	public static void main(String[] args) {
		B bb = new B(1, 2, 3);
		System.out.printf("%d, %d, %d\n", bb.i, bb.j, bb.k);
	}
}
// 说明了:子类B的构造函数中调用super,可以调用父类A的构造函数
class A {
	public int i;
	public int j;
}
class B extends A {
	public int k;
	public B() {}
	public B(int i, int j, int k) {
		// A(i, j); // error
		super(i, j); // OK
		this.k = k;
	}
}
public class TestSuper {
	public static void main(String[] args) {
		B bb = new B(1, 2, 3);
		System.out.printf("%d, %d, %d\n", bb.i, bb.j, bb.k); // => 1, 2, 3
	}
}
// super常犯错误
class A {
	public int i;
}
class B extends A {
	public int j;
	public B(int i, int j) {
		super(i); // error 因为父类A中没有有参构造方法
		this.j = j;
	}
	public void f(int i) { // 普通方法
		// super(i); // error 普通方法中不能调用父类的构造方法
	}
}
public class TestSuper {
	public static void main(String[] args) {
		B bb = new B(1, 2, 3);
		System.out.printf("%d, %d, %d\n", bb.i, bb.j, bb.k);
	}
}
// super常犯错误
class A {
	public int i;
	public A(int i) {
		this.i = i;
	}
}
class B extends A {
	public int j;
	public B(int i, int j) {
		//当你不写任何super时,系统会自动调用super(),这个时候因为父类A中有一个有参的构造方法,没有无参的,所有报错
		this.j = j;
	}
	public void f(int i) { // 普通方法
		// super(i); // error 普通方法中不能调用父类的构造方法
	}
}
public class TestSuper {
	public static void main(String[] args) {
		B bb = new B(1, 2, 3);
		System.out.printf("%d, %d, %d\n", bb.i, bb.j, bb.k);
	}
}
// super常犯错误
class A {
	public int i;
	public A() {}
	public A(int i) {
		this.i = i;
	}
}
class B extends A {
	public int j;
	public B(int i, int j) {
		this.j = j;
		super(i);  // error 因为super()要为第一条语句
		super(); // error 因为一个构造函数里面只能调用一个supper
	}
	public void f(int i) { // 普通方法
		// super(i); // error 普通方法中不能调用父类的构造方法
	}
}
public class TestSuper {
	public static void main(String[] args) {
		B bb = new B(1, 2, 3);
		System.out.printf("%d, %d, %d\n", bb.i, bb.j, bb.k);
	}
}

总结:

  • 每个子类构造方法的第一条语句,都是隐含地调用super(),如果父类没有这种形式的构造函数,那么在编译的时候就会报错
  • 如果显式的写出super()语句,则必须保证该语句是第一条语句,否则会出错
  • super()如果不写,则编译器会自动添加,所以此时如果父类没有无参的构造函数就会出错。
  • 既可以显式的写super(),前提是父类必须有无参的构造函数;也可以显式地写super(实参),前提是父类必须有带参数的构造函数
  • 调用父类的构造函数的语句必须借助于supper,不能直接写父类的类名
  • 一个构造函数不能写多个super语句

方法的重写

class A {
	public void f() {
		System.out.printf("AAAA\n");
	}
}
class B extends A {
	public void f() {
		super.f(); // 调用从父类继承过来的f方法 
		System.out.printf("BBBB\n");
	}
}
public class TestOver {
	public static void main(String[] args) {
		B bb = new B();
		bb.f(); // => AAAA    BBBB
	}
}
class A {
	public void f() {
		System.out.printf("AAAA\n");
	}
}
class B extends A {
	public void f() { // 重写父类方法
		System.out.printf("BBBB\n");
	}
}
public class TestOver {
	public static void main(String[] args) {
		B bb = new B();
		bb.f(); // =>  BBBB
	}
}
  • 方法重写:指在子类中重新定义父类中已有的方法
  • 重写方法必须二和被重写方法具有相同的方法名称、参数列表和返回值类型
  • 子类中不允许出现于父类同名同参数但不同返回类型的方法,如果出现,编译时会报错。
  • 重写方法时,不能使用比父类中被覆盖的方法更严格的访问权限

方法重写实例

class Human {
	private String name;
	private int age;

	public Human() {
	}
	public Human(String name, int age) {
		this.name = name;
		this.age = age;
	}
	public void setName(String name) {
		this.name = name;
	}
	public void setAge(int age) {
		this.age = age;
	}
	public String getInfo() {
		String strInf = name + ":" + age;
		return strInf;
	}
}
class Student extends Human {
	public String school;
	public Student() {}
	public Student(String name, int age, String school) {
		// this.name = name; //error 因为他们是私有的
		// this.age = age;
		super(name, age);
		this.school = school;
	}
	public void setSchool(String school) {
		this.school = school;
	}
	public String getInfo() {
		// String strInf = name + ":" + age + ":" + school; // error ,因为是私有的
		String strInf = super.getInfo() + ":" + school;
		return strInf;
	}
}
public class TestStudent {
	public static void main(String[] args) {
		Student st1 = new Student("张三", 22, "酱菜");
		System.out.printf("%s\n", st1.getInfo()); // => 张三:22:酱菜
	}
}