1、方法的重写(override)
子类可以重写(覆盖)继承自父类的方法,即方法名和参数列表与父类的方法相同,但方法的实现不同。
1.1、重写方法的调用
重写方法被调用时,看对象的类型,而不管是通过子类的引用调用还是通过父类的引用调用。
子类在重写父类的方法时,可以通过super关键字调用父类的版本。
class Foo{
public void f(){
System.out.println("Foo.f()");
}
}
class Goo extends Foo{
public void f(){
super.f();
System.out.println("Goo.f()");
}
}
Foo obj2 = new Goo();
obj2.f();
输出的结果:
Foo.f()
Goo.f()
子类重写方法中的super.f();调用了父类的版本。这样的语法通常用于子类的重写方法在父类方法的基础上进行功能扩展。
1.2、重写的规则
重写需要遵循“一大两小两同”规则(一般都是一模一样的):
1、一大:子类方法的访问权限大于或等于父类的。——-访问修饰符
2、两小:
(1)子类方法的返回值类型小于或等于父类的。
1.1)void和基本类型时,必须相同。
1.2)引用类型时,小于或等于。
(2)子类方法抛出的异常小于或等于父类的。——–异常
3、两同:方法名称相同;参数列表相同。
1.3、重写和重载
重写:父子类中,方法名相同,参数列表相同,方法体不同。遵循“运行期”绑定,根据对象的类型调用不同方法。
重载:一个类中,方法名相同,参数列表不同,方法体不同。遵循“编译期”绑定,根据引用的类型绑定不同方法。
package oo.day04;
public class OverloadOverrideDemo {
public static void main(String[] args) {
Aoo o = new Boo(); //向上造型
//重载时,看类型
//重写时,看对象
Coo c = new Coo();
c.t(o);
}
}
class Coo{
void t(Aoo o){
System.out.println("父类参数");
o.show();
}
void t(Boo o){
System.out.println("子类参数");
o.show();
}
}
class Aoo{
void show(){
System.out.println("父类show");
}
}
class Boo extends Aoo{
void show(){
System.out.println("子类show");
}
}
运行结果:
父类参数
子类show
2、包的概念
2.1、package
package 包名;
(1)作用:避免类的命名冲突
(2)包名可以有层次结构,在一个包中可以包含另外一个包。
(3)建议:包名所有字母都小写
(4)类的完全限定名:包名.类名
项目非常大的时候,建议:域名反写.项目名称.模块名称.类名
2.2、import
import 类的全局限定名(即包名+类名);
(1)作用:声明类/引入类
(2)同包中的类可以直接访问
不同包中的类想访问:
2.1)类的全称——–太繁琐(不建议)
2.2)先import声明类再访问类(建议)
3、访问控制修饰符(封装)
public:公开的,任何类
protected:受保护的,本类、同包类、子类
默认的:什么也不写,本类、同包类
private:私有的,本类
类的访问修饰符:public和默认的
类成员的访问修饰:如上4种都可以
protected和private可以用于修饰内部类。
4、static:静态的
(1)静态变量
1.1)由static修饰
1.2)属于类的,存在方法区中,只有一份
1.3)常常通过类名.来访问
1.4)何时用:所有对象的数据都一样时使用
(2)静态方法
2.1)由static修饰
2.2)属于类的,存在方法区中,只有一份
2.3)常常通过类名.来访问
2.4)没有隐式的this传递
静态方法中不能直接访问实例成员
2.5)何时用:方法的操作仅与参数相关而与对象无关时使用
(3)静态块
3.1)由static修饰
3.2)属于类的,类被加载期间自动执行
类只被加载一次,所以静态块也只执行一次
3.3)何时用:常常用于加载/初始化静态资源(图片、音频、视频…)
package oo.day04;
//static演示
public class StaticDemo {
public static void main(String[] args) {
/*
Hoo o1 = new Hoo();
//o1.show(); //1 1
Hoo o2 = new Hoo();
//o2.show(); //1 2
System.out.println(o1.b); //不建议
System.out.println(o2.b); //不建议
System.out.println(Hoo.b); //建议通过类名访问
//System.out.println(Hoo.a); //错误
*/
/*
Ioo.say();//静态方法由类名点来访问
//Ioo.show(); //错误,必须由对象来访问
*/
Joo o1 = new Joo();
Joo o2 = new Joo();
Joo o3 = new Joo();
}
}
class Joo{ //static块
Joo(){
System.out.println("111");
}
static{ //加载类的时候被执行,只执行一次
//因为类只被加载一次
System.out.println("静态代码块");
}
}
class Ioo{ //static方法
int a; //实例变量
static int b; //静态变量
void show(){
a++; //隐式的this传递过来
b++;
}
static void say(){
b++;
//a++; //错误,没有隐式this传递
//没有对象,而a属于对象的,所以错
}
}
class Hoo{ //static成员变量
int a;
static int b;
Hoo(){
a++;
b++;
}
void show(){
System.out.println(a);
System.out.println(b);
}
}
5、final:不能变
修饰变量:变量不能被改变。final修饰成员变量,有两种方式初始化:
(1)声明同时初始化。
(2)在构造函数中初始化。
修饰方法:方法不能被重写。
修饰类:类不能被继承。
package oo.day04;
//final演示
public class FinalDemo {
public static void main(String[] args) {
}
}
class Zoo{}
final class Xoo extends Zoo{} //可以继承别的类
//class Yoo extends Xoo{}//错误,final修饰类不能被继承
class Loo{ //final修饰方法---不可被重写
void show(){}
final void say(){}
}
class Moo extends Loo{
void show(){}
//void say(){} //错误,final方法不能被重写
}
class Koo{ //final修饰变量---不能改变,用得比较少
final int a = 5; //声明同时初始化
final int b;
Koo(){
b = 5; //先声明,再在构造中初始化
}
void show(){
final int c; //应用率几乎为零
//System.out.println(c);//错误,c没有值
c = 5;
System.out.println(c);
}
void say(){
//a = 88; //错误,final修饰的变量不能改变
}
}
static final修饰的成员变量称为常量,必须声明的同时初始化,不可被改变。会在编译期被替换。
package oop.day05;
public class StaticFinalDemo {
public static void main(String[] args) {
//编译时,直接将Aoo.PI替换为3.14159
System.out.println(Aoo.PI);
//在方法区中加载Aoo.class,以及static成员,以及方法
System.out.println(Aoo.num);
}
}
class Aoo{
//声明常量,必须声明同时初始化;建议所有字母大写。
static final double PI = 3.1415926;
static int num = 5;
}