Java知识点(九):方法的重写、重写和重载的区别、package、import、public、private、protected、默认访问控制符、static、final


Java语言基础

包括方法的重写(Override)、重写和重载的区别、访问控制(package、import、public、private、protected、默认访问控制符、访问控制修饰符对比)、静态变量、静态方法、静态块、成员变量和静态变量的区别、修饰成员变量、修饰方法、修饰类。


一、方法的重写(Override)

1)子类可以重写(覆盖)继承来自父类的方法,即方法名和参数列表与父类的方法相同,但实现方式不同

2)当子类对象的重写方法被调用时,无论是通过子类的引用调用还是通过父类的引用调用,运行的都是子类重写后的方法

public class Ooo {

	public static void main(String[] args) {
		Aoo o1 = new Boo(); 
		Boo o2 = new Boo();
		o1.show(); //结果为Java!
		o2.show(); //结果为Java!
	}

}

class Boo extends Aoo{ 
	void show() {
		System.out.println("Java!");
	}
}

class Aoo{ 
	void show() {
		System.out.println("Python!");
	}
}

在这里插入图片描述

3)在子类重写的方法中,可以通过super关键字调用父类的“原始”方法

public class Ooo {

	public static void main(String[] args) {
		Aoo o1 = new Boo(); 
		o1.show(); //Python!Java!
	}

}

class Boo extends Aoo{ 
	void show() {
		super.show(); //调用父类show方法,执行子类show方法会打印出Python!Java!
		System.out.print("Java!");
	}
}

class Aoo{ 
	void show() {
		System.out.print("Python!");
	}
}

在这里插入图片描述

代码示例:


public class OverrideDemo {

	public static void main(String[] args) {
		Aoo o1 = new Aoo();
		o1.show(); //父类show
		
		System.out.println();
		
		Boo o2 = new Boo();
		o2.show(); //父类show 子类show!
		
		System.out.println();
		
		Aoo o3 = new Boo();
		o3.show(); //父类show 子类show!

	}

}

/*
 * 重写需要遵循“两同两小一大”原则:一般都是一模一样的
 * 1.两同:方法名称相同;参数列表相同,不同方法体
 * 2.两小:
 *   1)子类方法的返回值类型小于或等于父类的
 *     1.1)void和基本类型时,必须相同
 *     1.2)引用类型时,小于或等于
 *   2)子类方法抛出的异常小于或等于父类的-----异常
 * 3.一大:子类方法的访问权限大于或等于父类的-----访问修饰符
 */

class Aoo{
	void show(){
		System.out.println("父类show");
	}
}

class Boo extends Aoo{
	void show(){
		super.show(); //调用父类的show方法
		System.out.println("子类show");
	}
}

//父类大,子类小
class Coo{
	void sayHi() {	}
	double show() {return 0.0;}
	Coo test() {return null;}
	Doo say() {return null;}
}

class Doo extends Coo{
	void sayHi() {	} //void时必须相同
	double show() {return 0.0;} //基本类型时必须相同
	//int show() {return 0.0;} //编译错误
	Doo test() {return null;} //小于父类
	//Coo say() {return null;} //编译错误,引用类型时必须小于或等于
}

在这里插入图片描述

二、重写和重载的区别

1)重写:父子类中,方法名相同,参数列表相同,不同方法体

遵循“运行期”绑定,根据对象的类型调用方法

2)重载:一个类中,方法名相同,参数列表不同,不同方法体

遵循“编译期”绑定,根据引用的类型绑定方法


public class OverrideDemo {

	public static void main(String[] args) {
		//重载看引用类型,重写看对象类型
		//o的引用类型是Eoo,所以输出父型参数
		//o指向的对象类型是Foo,所以o.show()方法走的是Foo类中的方法,输出子类show
		Goo goo = new Goo();
		Eoo o = new Foo(); //向上造型
		goo.test(o); //父型参数   子类show 

	}

}

class Goo{
	void test(Eoo o) { //重载
		System.out.println("父型参数");
		o.show();
	}
	void test(Foo o) { //重载
		System.out.println("子型参数");
		o.show();
	}
	
}

class Eoo{
	void show() {
		System.out.println("父类show");
	}
}

class Foo extends Eoo{
	void show() { //重写
		System.out.println("子类show");
	}
}

在这里插入图片描述

三、访问控制

3.1、package

1)作用:避免类的名称冲突

2)建议:包名所有字母都小写

3)类的完全限定名:包.类名

4)包名可以有层次结构,在一个包中可以包含另外一个包

5)创建包名规范

org.apache.commons.lang.StringUtil
StringUtil:类名
lang:模块的名称信息
commons:项目名称信息
org.apache:公司或组织的信息(公司或组织的域名反写)

3.2、import

1)作用:声明类/引入类

2)同包中类可以直接访问,不同包中的类想访问

2.1)先import声明类再访问类(建议),可以用“*”声明该包中所有类的全称

import org.apache.commons.lang.StringUtil
import org.apache.commons.lang.*

2.2)类的全称------太繁琐(不建议)

org.apache.commons.lang.StringUtil S = new org.apache.commons.lang.StringUtil();

3.3、public

公开的,修饰的成员变量和方法可以在任何类中调用

class Aoo{
	public int a;
	public void show() {}
}

3.4、private

私有的,修饰的成员变量和方法仅仅只能在本类中调用

class Boo{
	private int b;
	private void print() {}
}

3.5、protected

受保护的,修饰的成员变量和方法可以被子类及同一个包中的类使用

class Coo{
	protected int c;
	protected void say() {}
}

3.6、默认访问控制符

即不书写任何访问控制符,默认访问控制的成员变量和方法可以被同一个包中的类使用

class Doo{
	int d;
	void sayHi() {}
}

代码示例:

//类的访问修饰:public和默认的
//类成员的访问修饰:4种都可以用
package oo.day04;

public class Hoo {
	public int a; //任何类
	protected int b; //本类、子类、同包类
	int c; //本类、同包类
	private int d; //本类
	
	void show() {
		a = 1;
		b = 2;
		c = 3;
		d = 4;
	}

}

class Ioo{ //演示private
	void show() {
		Hoo o = new Hoo();
		o.a = 1;
		o.b = 2;
		o.c = 3;
		//o.d = 4; //编译错误
	}
}

package oo.day04.vis;
import oo.day04.Hoo;

public class Joo { //同包
	void show() {
		Hoo o = new Hoo();
		o.a = 1;
		//o.b = 2; //编译错误
		//o.c = 3; //编译错误
		//o.d = 4; //编译错误
	}
}

class Koo extends Hoo{ //演示protected
	void show() {
		a = 1;
		b = 2;
		//c = 3; //编译错误,不同包
		//d = 4; //编译错误,不同包
	}
}

3.7、访问控制修饰符对比

1)修饰类可以使用public和默认方式

2)public修饰的类可以被任何类使用;默认修饰的类只可以被同一个包中的类使用

3)protected和private可以用于修饰内部类

修饰符本类同一个包中类子类其他类
public可以访问可以访问可以访问可以访问
protected可以访问可以访问可以访问不能访问
private可以访问可以访问不能访问不能访问
默认可以访问不能访问不能访问不能访问

建议:数据私有化private,行为公开化public

有一个姓名变量age,如果将age定义为public,其它类中可以调用这个age参数,并随意修改;如果将age定义为private,再定义两个方法,一个修改,一个查看,虽然其它类还以可以修改这个age值,但是方法里可以控制修改规则

//创建Person类,定义age变量,即两个方法
public class Person {
    private int age;

    public void setAge(int age){
        if(age<0||age>100){
            return;
        }
        this.age = age;
    }
    public int getAge(){
        return age;
    }
}
//创建Person类对象,并调用方法,对age进行修改、查看
public class Test {
    public static void main(String[] args) {
        Person man = new Person();
        man.setAge(300);
        System.out.println(man.getAge());  // 0;默认值为0,设置300不符合规则,所以age还是默认值
    }
}

在这里插入图片描述

四、static:静态的

4.1、静态变量

1)由static修饰

static int b;

2)属于类的变量,存在方法区中,只有一份

3)常常通过类名.来访问static变量

4)何时用:所有对象的数据都一样时使用

//静态变量演示
public class Ooo {

	public static void main(String[] args) {
		Loo o1 = new Loo();
		o1.show(); //结果为a=1,b=1;开始默认都为0,new Loo()时,调用了无参构造,+1
		Loo o2 = new Loo();
		o2.show(); //结果为a=1,b=2;创建新对象,a在推区重新创建一块内存,b在方法区不动,new Loo()时,a开始默认为0,b为1,在之前被调用过一次
		System.out.println(Loo.b); //结果为2,建议通过类名来访问
		System.out.println(o1.b); //结构为2,不建议通过引用来访问
	}

}

class Loo{ 
	int a;
	static int b; //声明静态变量
	Loo(){
		a++;
		b++;
	}
	void show() {
		System.out.println("a="+a);
		System.out.println("b="+b);
	}
}

在这里插入图片描述

在这里插入图片描述

4.2、静态方法

1)由static修饰

2)属于类的,存在方法区中,只有一份

3)常常通过类名.来访问

4)没有隐式this传递,静态方法中不能直接访问实例成员

5)何时用:方法的操作仅与参数相关而与对象无关时使用

class Aoo{
	int a; //实例变量-----对象点来访问
	static int b; //静态变量-----类名点来访问
	void show() { //实例方法-----隐式this
		this.a++;
		Aoo.b++; //默认有个Aoo.
	}
	static void test() { //静态方法
		//a++; //编译错误,没有this就意味着没有对象,而实例成员必须通过对象点来访问,所以静态方法中不能直接访问实例成员
		//show(); //编译错误
		Aoo.b++; //默认有个Aoo.
	}
}

4.3、静态块

1)由static修饰

2)属于类的,类被加载期间自动执行,类只能被加载一次,所以静态块也只能执行一次

3)何时用:常常用户加载/初始化静态资源(图片、音频、视频…)

public class Ooo {

	public static void main(String[] args) {
		Noo o3 = new Noo(); //输出静态块和构造方法
		System.out.println();
		Noo o4 = new Noo(); //输出构造方法
	}

}

class Noo{
	static {
		System.out.println("静态块");
	}
	Noo(){
		System.out.println("构造方法");
	}
}

在这里插入图片描述

4.4、成员变量和静态变量的区别

成员变量(实例变量)

1)属于对象的,存在堆中

2)有几个对象就有几个实例变量

3)必须通过对象名.来访问

静态变量

1)属于类的,存在方法区中

2)只有一份

3)常常用类名.来访问

class Aoo{
	int a; //实例变量-----对象点来访问
	static int b; //静态变量-----类名点来访问
}

五、final:不能变

5.1、修饰成员变量

修饰成员变量不能被改变。该成员变量需要在初始化时赋值,对象一旦创建即不可改变

/*
 * final修饰成员变量,两种方式初始化:
 *   1)声明的同时初始化
 *   2)构造方法中初始化
 * final修饰局部变量,只要在用之前初始化即可
 */
class Ooo{
	final int a = 5; //声明的同时初始化
	final int b;
	Ooo(){
		b = 5; //构造方法中初始化
	}
	void show() {
		final int c; //用之前赋值即可,不用可以不赋值
		//a = 55; //编译错误,final的变量不能被改变
	}
}

5.2、修饰方法

1)修饰方法不能被重写

2)意义:防止子类在定义新方法时造成“不经意”的重写

class Poo{
	final void show() {	}
	void test() {	}
}

class Qoo extends Poo{
	//void show() {	} //编译错误,final的方法不能被重写
	void test() {	}
}

5.3、修饰类

1)修饰的类不能被继承

2)意义:可以监控滥用继承对系统造成的危害

final class Roo{}
//class Soo extends Roo{} //编译错误,final的类不能被继承

class Too{}
final class Uoo extends Too{} //正确,final的类可以继承别人的