类和继承

1、继承

1、概述:将多个类中存在相同的属性和行为时,将这些内容抽取到单独一个类中,再写其他类的时候无需再定义这些属性和行为,只要继承那个类就好。
语法 :

class 子类名 extends 父类名
  • 单独这个类称为父类、基类、超类,这多个继承自父类的类称为子类、派生类
  • 有了继承之后,我们可以在一个已经存在的类继承上还可以定义自己的新成员。

2、好处:提高了代码的复用性、可维护性、让类与类之间产生了关系(其实也是一个弊端,因为类的耦合性增强了)

3、开发的原则:低耦合、高内聚
低耦合:类与类的关系(当继承的父类改变了,子类继承了过来,可能子类并不需要这个)
高内聚:就是自己完成某件事的能力

4、 特点:

  • java只支持单继承,不支持多继承
  • java支持多层继承

5、注意:

  • 如果要构造子类,必须要先构造父类
    原因:继承就是为了方便用父类的成员变量和方法,而父类的的成员变量如果不进行初始化那么子类咋用呢,所以要通过构造方法来对父类数据进行初始化。
  • 子类可以继承父类所有除构造外所有非私有的东西,对于私有的成员,可以封装到公共方法中访问。
  • 子类虽然不能继承父类的构造,但是可以通过super()关键字访问父类的构造方法。
  • 不要为了部分功能区选择继承,继承中体现的是一种 is A的关系。

5、继承成员变量的关系

  • 子类中的成员命名和父类中一样时的查找顺序:先在子类的局部找、再再子类的成员找,再找不到就到父类的成员找,如果还是没有就会报错。

6、方法重写(父类这个方法我子类要用,并且还要加新的东西,于是就重新写一个一模一样的方法,把以前的操作继承过来,然后加上自己的新的操作,这样就把父类的这个方法给覆盖了)

  • 子类出现了和父类中方法声明一模一样的方法
  • 应用:当子类需要父类的功能,而功能主体子类有自己特有内容时,可以重写父类的方法,这样既沿袭了父类的功能又定义了子类特有的内容。
  • 子类对象调用方法的时候,先找子类本身,再找父类。
    eg:一个简单实例感受下
class Phone{
	public void call(String name){
		System.out.print("给"+name+"打电话");
	}
}

class NewPhone extends Phone{
	public void call(String name){
	super.call(name);
	//System.out.println("给"+name+"打电话");
	//新手机继承自手机,它首先具备手机本来的功能,然后又有了自己的新功能,所以以前的功能不必再写一遍,只需要继承过来就好,这就是继承的优点之一啦。
	System.out.println("可以视频聊天");
	}
}
class Test{
	public static void main(String[] args){
		NewPhone n = new NewPhone();
		n.call("小黑");
		//执行结果:给小黑打电话,可以视频聊天
	}
}

注意:

  • 父类中的私有方法不能被重写(因为父类私有方法子类根本就无法继承)
  • 子类重写父类方法的时候权限不能更低

7、构造方法间的关系

  • 子类中的所有构造方法都会默认首先访问父类的空参方法。
    所有类都会默认继承自一个Object的类,并且这个类的构造就是无参的。
class Father{
	public Father(){
		System.out.println("这是father的无参构造");
	}
	public Father(String neme){
		System.out.println("这是father的带参构造");
	}
}
class Son extends Father{
	public Son(){
		System.out.println("这是son的无参构造");
	}
	public Son(String sex){
	//这里其实默认有一个super();
	//调用父类无参构造
		System.out.println("这是son的带参构造");
	}
}

public class Test{
	public static void main(String[] args){
		Son son1 = new Son();//执行结果
	//这是father的无参构造
	//这是father的带参构造
		Son son2 = new Son("man");
		//这是father的无参构造
		//这是son的带参构造
	}
}

  • 如果父类没有无参构造呢?(也就是你显示的给父类提供了带参构造,而编译器不会再给你提供无参的时候咋办? )
    //方法一:子类通过super去显示的调用父类的其他带参构造,对父类的数据进行初始化
    //方法二:间接调用,就是说如果子类中有一个构造去调用了父类的带参构造,那么其他构造可以借助this关键字去调用自己本类的构造达到父类构造。
    //值得注意的是你的super和this都应该放在第一行,因为该句是对父类成员进行初始化,而如果你没放在第一行,第一行会默认有一个super(),这样你后面再次super(…)就会对父类数据进行两次初始化,所以必须放在第一行。
class Father{
	public Father(String name){
		System.out.println("父类的带参构造");
	}
}
class Son extends Father{
	public Son(){
		//super()默认调用父类无参
		//方法一 super("name");
		//方法二super("name");
		System.out.println("子类的无参构造");
	}
	public Son(String sex){
		//super()默认调用父类无参
		//方法一 super("name")
		//方法二 this()调用本类无参
		System.out.println("子类的带参构造");
	}
}
public class TestDemo{
	public static void main(String[] args){
	Son son3 = new Son();
	Son son4 = new Son("man");
	}
}

2、关于类的知识点

1、一个类的初始化过程

  • 成员变量的初始化
    成员变量的初始化(默认初始化、显示初始化、构造方法的初始化

  • 子父类的初始化(分层初始化)
    先进行父类的初始化,然后进行子类的初始化

class X{
	Y b = new Y();
	public X(){
		System.out.println("X");
	}
}
class Y{
	public Y(){
		System.out.println("Y");
	}
}
class Z extends X{
	Y y = new Y();
	public Z(){
	//super();虽然子类构造中默认有这个,但是在初始化的时候,
	//不是按那个顺序进行,而是分层初始化,它仅仅代表要先初始化父类数据后再初始化子类。
		System.out.println("Z");
	}
	public static void main(String[] args){
		new Z();
		//执行结果 YXYZ
	}
}

newZ() —>Z类有继承关系—>X—>先走X的成员变量,是引用类型的b—>X的构造—>Z的成员变量,是引用类型y—>Z的构造
2、关于代码块(静态、实例、构造)

  • 本地代码块:方法内部的代码块
  • 实例代码块:类内方法外(初始化类的实例成员,可以访问静态和非静态,优先于构造)
  • 静态代码块:初始化静态的数据成员,静态的只第一次实例化的时候初始化一次
  • 同步代码块

eg:
其中,执行顺序是:
静态代码块>实例代码块>构造代码块>本地代码块

class Fu {
	static {
		System.out.println("静态代码块Fu");
	}

	{
		System.out.println("构造代码块Fu");
	}

	public Fu() {
		System.out.println("构造方法Fu");
	}
}

class Zi extends Fu {
	static {
		System.out.println("静态代码块Zi");
	}

	{
		System.out.println("构造代码块Zi");
	}

	public Zi() {
		System.out.println("构造方法Zi");
	}
}

class ExtendsTest2 {
	public static void main(String[] args) {
		Zi z = new Zi();
		//静态代码块Fu
		//静态代码块Zi
		//构造代码块Fu
		//构造方法Fu
		//构造代码块Zi
		//构造方法Zi
	}
}
发布了52 篇原创文章 · 获赞 6 · 访问量 1472

猜你喜欢

转载自blog.csdn.net/qq_40488936/article/details/103066602