9.29-Static关键字与继承

Static关键字

特点

  1. static是一个修饰符,用于修饰成员

  2. static修饰的成员被所有的对象所共存

  3. static优先于对象而存在,因为static修饰的成员随着类的加载已经存在了

  4. static修饰的成员多了一种调用方式,可以直接被类名.静态成员的方式来调用

  5. static修饰的数据是共享数据,对象中储存的数据是特有数据

例子

package day02;

public class StaticDemo {
	public static void main(String[] args) {
		Person.method();
		Person p = new Person("张三",23);
		p.show();
	}
}
class Person{//描述中国人
	private String name;
	private int age;
	static String country = "CN";//国籍  静态变量
	public Person(String name,int age) {
		this.name = name;
		this.age = age;
	}
	/*
	 * ①静态方法中只能访问静态的成员
	 * ②静态方法中不能使用this和super关键字
	 */
	public /*static*/ void show() {
		System.out.println
		(Person.country+":"+this.name+":"+this.age);
	}
	public static void method() {
		System.out.println(Person.country);
	}
}

成员变量与静态变量的区别

  1. 两个变量的生命周期不同

    • 成员变量随着对象的创建而存在,随着对象的被回收而回收

    • 静态变量随着类的加载而存在,随着类的消失而消失

  2. 调用方式不同

    • 成员变量只能被对象调用

    • 静态变量可以被对象调用,也可以被类名调用

  3. 别名不同

    • 成员变量也叫实例变量

    • 静态变量也叫做类变量

  4. 数据的存储位置不同

    • 成员变量的数据储存在堆内存的对象中,也叫做对象的特有数据

    • 静态变量数据储存在方法区的静态方法区(数据共享区)中,所以也叫做对象的共享数据

静态的使用场景

  1. 静态变量

    • 当分析对象中所具备的值都是相同的,这时就可以被静态修饰,只要数据在对象中是不同,就是对象的特有数据,必须储存在对象中,是非静态的

  2. 静态方法

    • 方法中是否静态修饰,参考该方法是否有访问到对象的特有数据,如果有,就定义成非静态的,如果没有则定义成静态。

静态代码块(定义在类中)

package day9_29;

public class StaticCodeDemo {
	public static void main(String[] args) {
		new StaticCode().show();
		new StaticCode().show();
	}
	}
class StaticCode{
	/*
	 * 静态代码块
	 * 静态代码块随着类的加载而执行,且只执行一次
	 * 作用:给类进行初始化
	 */
	static {
		System.out.println("Hello,Static Code!");
	}
	void show() {
		System.out.println("Show Run!");
	}
}

构造代码块(定义在类中)

package day9_29;

public class ConsCodeDemo {
	public static void main(String[] args) {
		baby b1 = new baby();
		b1.speak();
		baby b2 =new baby("旺财");
		b2.speak();
		baby b3 = new baby("张三",3);
		b3.speak();
	}
}
class baby{
	{//构造代码块,用于给全体对象进行初始化
		cry();
	}
	private String name;
	private int age;
	public baby(){
		this.name="baby";
		this.age=1;
//		cry();
	}
	public baby(String name) {
		this.name=name;
//		cry();
	}
	public baby(String name,int age) {
		this.name=name;
		this.age=age;
//		cry();
	}
	public void speak() {
		System.out.println(name+","+age);
	}
	public void cry() {
		System.out.println("wawa");
	}
}

面试小问题

一个类中有静态代码块、构造代码块、构造器,它们执行的先后顺序是什么?

静态代码块、构造代码块、构造器

继承(extends)

例子

package day9_29;

public class ExtendsDemo01 {
	public static void main(String[] args) {
		Student s = new Student();
		s.name="张三";
		s.age=23;
		s.study();
	}
}
	//父类
class People{
	String name;
	int age;
}
	//学生类(子类)
class Student extends People{
	void study() {
		System.out.println("student study,"+name+","+age);
	}
}
	//工人类(子类)
class Worker extends People{
	void work() {
		System.out.println("worker work,"+name+","+age);
	}
}

好处

  1. 提高了代码复用性

  2. 让类与类之间产生了父子关系(继承关系/父子关系),给面向对象的第三个特征多态提供了前提

Java中的单继承/多继承

Java中支持单继承,不直接支持多继承,但是对C++中的多继承机制进行了改良(多实现)

单继承

一个子类只能有一个直接父类

多继承

一个子类可以有多个直接父类(Java中不允许)

多继承会产生调用的不确定性,所以Java中不受支持

多层(重)继承

image-20220929174927503

A继承B,B继承C,C继承D,此时,A、B、C都拥有D的内容继承

在子父类中成员的特点体现

成员变量

当本类中成员和局部变量重名时,使用this区分重名变量;当子父类中的成员变量重名时,使用super区分父类

简单来说,this可以在本类访问本类的成员变量和成员方法,super可以在子类访问父类的成员变量和方法

this代表的是一个本类对象的引用(当前对象)

super代表的是一个父类空间

package day9_29;

public class ExtendsDemo02 {
	public static void main(String[] args) {
		Son s = new Son();
		s.show();
	}
	}
class Father{
	int num=4;
}
class Son extends Father{
	int num=5;
	void show() {
		System.out.println(this.num+","+super.num);
	}
	
}
package day9_29;

public class ExtendsDemo02 {
	public static void main(String[] args) {
		Son s = new Son();
		s.show();
	}
	}
class Father{
	private int num=4;
	public int getNum() {
		return num;
	}
	public void setNum(int num) {
		this.num=num;
	}
}
class Son extends Father{
	int num=5;
	void show() {
		System.out.println(this.num+","+super.getNum());
	}
}

注意,super与this均可以正常调用父类方法,但this是由继承而来的间接调用,super则是直接调用

成员方法

特点

当子父类中,出现一模一样的方法时,会运行子类中的方法,这种现象称之为覆盖操作,也称之为方法的重写;重写是方法在子父类中的特性

方法的两个特性:

  1. 重载,发生在同一个类中(overload)

  2. 重写,发生在子类中(override)

package day9_29;

public class ExtendsDemo03 {
	public static void main(String[] args) {
		Son s = new Son();
		s.show();
		s.show();
	}
}
class Father{
	void show(){
		System.out.println("father show run");
	}
}
class Son extends Father{
	void show(){
		System.out.println("son show run");
	}
}

注意事项

  • 子类重写父类方法时,子类权限必须大于等于父类权限

  • 静态只能覆盖静态或被静态覆盖

构造器

子类继承了父类,获取到父类的内容(属性),所以在使用自己的父类属性之前,要看父类是如何在自己的构造器中对自己的属性进行初始化的;所以在子类构造对象时,必须访问父类中的构造器,为了完成这个必须的动作,子子类中隐入super(语句),super()调用的是父类的无参构造器,那么必须必须在子类构造器中使用super明确的调用父类的有参构造器,在()中增加参数即可。

同时子类构造器中,如果使用了this调用了本类的其他构造器,那么super则无效,因为super与this都是必须被定义在第一行,所以只能有一个,但是可以保证的是,子类中肯定有其他的构造器能够访问父类的构造器

例子

package day02;

public class ExtendsDemo05 {
	public static void main(String[] args) {
		Son s = new Son();
	}
}
class Father{
	int num;
	public Father() {
		num = 10;
		System.out.println("Father run");
	}
	public Father(int x) {
		System.out.println("Father run"+x);
	}
}
class Son extends Father{
	/*
	 * 在子类构造器中的第一行有一个默认的隐式语句
	 * super(),super()调用的是父类的无参构造器
	 * 如果父类中没有无参构造器,那么必须在子类
	 * 构造器中使用super明确的调用父类的有参构造器
	 * 在()中指定参数即可
	 */
	public Son() {
//		super(5);
		System.out.println("Son run"+num);
	}
	public Son(int x) {		
		this();
//		super();//必须定义在第一行(语法规则)		
		System.out.println("Son run"+x);
	}
}

最后更新于