6-面向对象

116 阅读21分钟

面向对象

1. 面向过程:Process-oriented programming

强调的是功能行为,以函数为最小单位,考虑怎么做

2. 面向对象:Object-Oriented Programming

将功能封装进对象,强调具备功能的对象,以类/对象为最小单位,考虑谁来做

  • 程序员从面向过程的执行者转化为面向对象的指挥者
  • 根据问题需要,选择问题所针对的现实世界中的实体
  • 从实体中寻找解决问题相关的属性和功能,这些属性和功能就形成了概念世界中的类
  • 类的实例化就是对象,对象是计算机世界中解决问题的最终工具。类 = 抽象概念的人;对象 = 实实在在的某个人
  • 面向对象程序设计的重点是类的设计。类的设计,就是类的成员的设计

3. 类和对象

类是对象的集合,对象是类的实例

  • 类是对一类事物的描述,是抽象的、概念上的定义
  • 对象是实际存在的该类事物的每个个体,因而也称为实例

引用类型的变量,只可能存储两类值:null 或 地址值(含变量的类型)

堆栈方法区.jpg

4. 理解“万事万物皆对象”

  1. 在Java语言范畴中,我们都将功能、结构等封装到类中,通过类的实例化,来调用具体的功能结构
  • Scanner, String等
  • 文件:File
  • 网络资源:URL
  1. 涉及到Java语言与前端Html、后端的数据库交互时,前后端的结构在Java层面交互时,都体现为类、对象

1、类和类的成员

6-1类和类的成员.png

1. 属性

1.1 成员变量和局部变量

局部变量和成员变量.jpg

1.2 静态变量

1.3 默认初始化值

1. 整型(byteshortintlong):0
2. 浮点型(floatdouble):0.0
3. 字符型(char):0  (或'\u0000'4. 布尔型(boolean):false
5. 引用数据类型(类、数组、接口):null

1.4 在内存中加载位置

静态属性:存在方法区的静态域中
非静态属性:加载到堆空间中
局部变量:加载到栈空间

2. 方法

2.1 方法重载:两同一不同

  • 同一个类,相同方法名
  • 参数列表不同:参数个数不同,参数类型不同
  • 跟方法的权限修饰符、返回值类型、形参变量名、方法体都没有关系

2.2 可变形参的方法

2.3 静态方法

3. 构造器

3.1 构造器的作用

  • 创建对象
  • 初始化对象的信息

3.2 说明

  • 如果没有显式的定义类的构造器的话,则系统默认提供一个空参的构造器
  • 一个类中定义的多个构造器,彼此构成重载
  • 一旦我们显式的定义了类的构造器之后,系统就不再提供默认的空参构造器
  • 一个类中,至少会有一个构造器。

4. 代码块

用来初始化类、对象

4.1 静态代码块

  • 初始化类的信息
  • 随着类的加载而执行,而且只执行一次,静态代码块的执行要优先于非静态代码块的执行
  • 静态代码块内只能调用静态的属性、静态的方法,不能调用非静态的结构
  • 如果一个类中定义了多个静态代码块,则按照声明的先后顺序执行

4.2 非静态代码块

  • 初始化对象信息

  • 随着对象的创建而执行,每创建一个对象,就执行一次非静态代码块

  • 非静态代码块内可以调用静态的属性、静态的方法,或非静态的属性、非静态的方法

  • 如果一个类中定义了多个非静态代码块,则按照声明的先后顺序执行

public class Block1 {
	public static void main(String[] args) {

		//静态代码块随着类的加载而执行,而且只执行一次
        //hello,static block-2 
        //hello,static block-1 
        //我是一个快乐的人!
//		String desc = Person.desc;

		//静态代码块随着类的加载而执行,而且只执行一次
		//hello,static block-2
		//hello,static block-1
		//我是一个快乐的人!
		//非static代码块:每创建一个对象,就执行一次非静态代码块
		//hello, block - 2
		//hello, block - 1
		//吃饭
		//我是一个快乐的人!
		Person p1 = new Person();
		
		/非static代码块:每创建一个对象,就执行一次非静态代码块
		//hello, block - 2
		//hello, block - 1
		//吃饭
		//我是一个快乐的人!
		Person p2 = new Person();

        //初始化类或对象的信息
		System.out.println(p1.age);//1
	}
}

class Person{
	String name;
	int age;
	static String desc = "我是一个人";
	
	public Person(){
	}
	public Person(String name,int age){
		this.name = name;
		this.age = age;
	}

	public void eat(){
		System.out.println("吃饭");
	}
	public static void info(){
		System.out.println("我是一个快乐的人!");
	}
    
	//非static代码块
    //可以调用静态的和非静态的结构
	{
		System.out.println("hello, block - 2");
	}
	{
		System.out.println("hello, block - 1");
		//调用非静态结构
		age = 1;
		eat();
		//调用静态结构
		desc = "我是一个爱学习的人1";
		info();
	}

	//static的代码块
	//只能调用静态结构
	static{
		System.out.println("hello,static block-2");
	}
	static{
		System.out.println("hello,static block-1");
		//调用静态结构
		desc = "我是一个爱学习的人";
		info();
		//不可以调用非静态结构
//		eat();
//		name = "Tom";
	}
}

5. 内部类

5.1 成员内部类

  • 静态的
  • 非静态的

5.2 局部内部类

  • 方法内
  • 代码块内
  • 构造器内

2、三大特性

6-2三大特性.png

1. 封装

1.1 私有化属性

私有化属性,并提供公共的方法来获取(get)和设置(set)此属性的中

1.2 私有化方法

私有化方法,不对外暴露的私有的方法

1.3 四种权限修饰符的作用范围

类只能使用 public 或 缺省修饰

  • public修饰的类可以在同一个module的不同的package下调用

  • 缺省修饰的类只能在同一个包下调用

graph TD
 
A(project) -->B1(module1)
A(project) -->B2(module2)
A(project) -->B3(module3)
B1 --> C1(package1)
B1 --> C2(package2)
B1 --> C3(package3)
B2 --> D1(package1)
B2 --> D2(package2)
B2 --> D3(package3)
C1 --> F1(package1)
C1 --> F2(package2)
C1 --> F3(package3)

四种权限修饰符.jpg

/* 
 * 同一个module下的 class:
 *
 * 1. class可以被同一个包下的其他类所调用
 * 2. public class可以被同一个module下的其他包中的类所调用
 */
/* 
 * 类中的成员:
 *
 * 1. private 只能在当前类中调用
 * 2. default 能在同一个包下使用(包括同一个包中定义的子类)
 * 3. protected 可以在同一个包下使用,以及可以在同一个module下的不同包的子孙类中使用
 */

package T1_encapsulation;//当前类所在包
public class Order {
    //属性
    private int orderPrivate;//只能在当前类中调用
    int orderDeafult;
    protected int orderProtected;
    public int orderPiblic;

    //方法
    private void methodPrivate(){//只能在当前类中调用
        orderPrivate = 1;
        orderDeafult = 2;
        orderProtected = 3;
        orderPiblic = 4;
    }

    void methodDeafult(){
        orderPrivate = 1;
        orderDeafult = 2;
        orderProtected = 3;
        orderPiblic = 4;
    }

    protected void methodProtected(){
        orderPrivate = 1;
        orderDeafult = 2;
        orderProtected = 3;
        orderPiblic = 4;
    }

    public void methodPiblic(){
        orderPrivate = 1;
        orderDeafult = 2;
        orderProtected = 3;
        orderPiblic = 4;
    }
}

class OrderSun extends Order{

    public void test(){
        orderDeafult = 22;//能在同一个包下使用(包括同一个包中定义的子类)
        orderProtected = 23;
        orderPiblic = 24;
        
        methodDeafult();//能在同一个包下使用(包括同一个包中定义的子类)
        methodProtected();
        methodPiblic();
    }
}


package s1_field.test;//当前类所在包
import T1_encapsulation.Order;
class OrderSun extends Order {
    public void test(){
        //methodDefault();//调不了
        methodProtected();//可以在同一个module下的不同包的子孙类中使用
        methodPiblic();
        
		//orderDefault = 31;//调不了
        orderProtected = 32;//可以在同一个module下的不同包的子孙类中使用
        orderPiblic = 33;
    }
}

1.4 JavaBean

/*
 * 1. JavaBean是一种Java语言写成的可重用组件。
 *
 * 2. JavaBean,是指符合如下标准的Java类:
 *		>类是公共的
 *		>有一个无参的公共的构造器
 *		>有属性,且有对应的get、set方法
 */

//类是公共的
public class TJavaBean {
    
    //私有的属性
    private String name;
    private int age;
    
    //无参的公共的构造器
    public TJavaBean(){
        
    }
    
    //对应的get、set方法
    public void setAge(int age){
        this.age = age;
    }
    
    public int getAge(){
        return age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

2. 继承

2.1 说明

一旦子类A继承父类B以后,子类A中就获取了父类B中声明的所有的属性和方法。

  • 特别的,父类中声明为private的属性或方法,子类继承父类以后,==仍然认为获取了父类中私有的结构。只有因为封装性的影响,使得子类不能直接调用父类的结构而已。==
  • 子类继承父类以后,还可以声明自己特有的属性或方法:实现功能的拓展。

2.2 子类对象实例化的全过程

  • 从结果上来看:(继承性)
    • 子类继承父类以后,就获取了父类中声明的属性或方法。
    • 创建子类的对象,在堆空间中,就会加载所有父类中声明的属性。
  • 从过程上来看:
    • 当我们通过子类的构造器创建子类对象时,我们一定会直接或间接的调用其父类的构造器,进而调用父类的父类的构造器,... 直到调用了java.lang.Object类中空参的构造器为止。正因为加载过所有的父类的结构,所以才可以看到内存中有父类中的结构,子类对象才可以考虑进行调用。
  • 虽然创建子类对象时,调用了父类的构造器,但是自始至终就创建过一个对象,即为new的子类对象

2.3 ==方法的重写==

  • 子类继承父类以后,可以对父类中同名同参数的方法,进行覆盖操作

  • 子类重写的方法的方法名和形参列表与父类被重写的方法的方法名和形参列表相同

  • 子类重写的方法的权限修饰符不小于父类被重写的方法的权限修饰符

  • 子类不能重写父类中声明为private权限的方法

  • 父类被重写的方法的返回值类型是void,则子类重写的方法的返回值类型只能是void

  • 父类被重写的方法的返回值类型是A类型,则子类重写的方法的返回值类型可以是A类或A类的子类

  • 父类被重写的方法的返回值类型是基本数据类型(比如:double),则子类重写的方法的返回值类型必须是相同的基本数据类型(必须也是double)

  • 子类重写的方法抛出的异常类型不大于父类被重写的方法抛出的异常类型

3. 多态

  • 对象的多态性:父类的引用指向子类的对象(或子类的对象赋给父类的引用)

  • 内存中实际上是加载了子类特有的属性和方法的,但是由于变量声明为父类类型,导致编译时,只能调用父类中声明的属性和方法,子类特有的属性和方法不能调用。

3.1 多态性的使用前提

  • 类的继承关系

  • 方法的重写

3.2 多态的使用1:虚拟方法的调用

编译期,只能调用父类中声明的方法,但在运行期,实际执行的是子类重写父类的方法

3.3 多态的使用2:向下转型

为了能够调用子类特有的属性和方法

  • 向上转型:多态

  • 向下转型:强转转换

3.4 instanceof

  • a instanceof A:判断对象a是否是类A的实例。如果是,返回true;如果不是,返回false

  • 使用情境:为了避免在向下转型时出现ClassCastException的异常,我们在向下转型之前,先进行instanceof的判断,一旦返回true,就进行向下转型。如果返回false,不进行向下转型

  • 如果类B是类A的父类,那么当a instanceof A为true时,则 a instanceof B也返回true.

public class Polymorphism1 {
    public static void main(String[] args) {

        Person p1 = new Person();
        //1. 多态:父类引用指向子类对象
        Person p2 = new Man();
        Person p3 = new Woman();

        /*
        对象的多态性: 内存中实际上是加载了子类特有的属性和方法的,但是由于变量声明为父类类型,
        导致编译时,只能调用父类中声明的属性和方法。子类特有的属性和方法不能调用
         */
        System.out.println(p2.id);//1001
        System.out.println(p3.id);//1001
        //调不了。不能调用子类所特有的方法、属性:编译时,p2是Person类型
        //p2.earnMoney();
        //p3.goShopping();

        //2. 虚拟方法的调用:编译时看的是父类,执行时是子类重写的父类的方法
        p1.eat();//人吃饭
        p2.eat();//男人多吃饭
        p3.eat();//少吃

        //如何才能调用子类特有的属性和方法?
        //向下转型:使用强制类型转换符
        Man m1 = (Man) p2;
        m1.earnMoney();
        System.out.println(m1.id);
        System.out.println(m1.isSmoking);

        //使用强转时会出现异常:ClassCastException
        //先用instanceof判断一下:判断是否是这个类以及这个类(父类)对象
        if(p3 instanceof Woman){
            Woman w1 = (Woman) p3;
            w1.goShopping();
            System.out.println(w1.id);
            System.out.println(w1.isBeauty);
        }

        if(p2 instanceof Woman){
            Woman w2 = (Woman) p2;
            w2.goShopping();
        }
    }
}

class Person{
    String name;
    int age;
    int id = 1001;

    public void eat(){
        System.out.println("人吃饭");
    }

    public void walk(){
        System.out.println("人走路");
    }
}

class Man extends Person{
    boolean isSmoking;
    int id = 1002;

    public void earnMoney(){
        System.out.println("男人要赚钱");
    }

    @Override
    public void eat() {
        System.out.println("男人多吃饭");
    }

    @Override
    public void walk() {
        System.out.println("直着走");
    }
}

class Woman extends Person{
    boolean isBeauty;
    int id = 1003;

    public void goShopping(){
        System.out.println("逛街");
    }

    @Override
    public void eat() {
        System.out.println("少吃");
    }

    @Override
    public void walk() {
        System.out.println("慢走");
    }
}
public class Polymorphism2 {
    public static void main(String[] args) {

        Base b1 = new Base();
        System.out.println(b1.count);//10
        b1.display();//10

        Sub s1 = new Sub();
        System.out.println(s1.count);//20
        s1.display();//20

        /*
        1. 内存中实际上是加载了子类特有的属性和方法的,但是由于变量声明为父类类型,
        导致编译时,只能调用父类中声明的属性和方法
        2. 当子类重写了父类的方法时,但是由于变量声明为父类类型,调用的虽然是父类中的方法,
        但执行的是子类重写父类的方法
         */
        Base b2 = s1;
        System.out.println(b2.count);//10
        b2.display();//20
    }
}

class Base{
    int count = 10;

    public void display(){
        System.out.println(count);
    }
}

class Sub extends Base{

    int count = 20;

    @Override
    public void display() {
        System.out.println(count);
    }
}

3.5 编译时多态和运行时多态

如果在编译时能够确定执行多态方法中的哪一个,称为编译时多态,否则称为运行时多态

3、抽象类

6-3抽象类和接口.png

  • abstact:抽象的
  • abstract可以用来修饰的结构:类、方法
  • abstract不能用来修饰:属性、构造器等结构
  • abstract不能用来修饰私有方法、静态方法、final的方法、final的类

3.1 抽象类

  • 抽象类不可被实例化
  • 抽象类不一定有抽象方法
  • 抽象类一定有构造器

3.2 抽象方法

  • 抽象方法只有方法的声明,没有方法体
  • 具有抽象方法的类一定是抽象类
  • 若子类重写了父类中的所有的抽象方法,则此子类方可被实例化
  • 若子类没有重写父类中的所有的抽象方法,则此子类也是个抽象类
public class AbstractTest {
    public static void main(String[] args) {
        //抽象类不可被实例化
        //Person p = new Person();//error

        //抽象类的实例化方式
        Person p = new Person() {
            @Override
            public void eat() {
                System.out.println("人吃饭");
            }
        };
        p.eat();

        //抽象类的子类(重写了抽象方法)实例化
        Student s = new Student("李三", 24);
        s.eat();
    }
}

//1. 定义抽象类:abstract
abstract class Creature{
    //2. 抽象类中可以有抽象方法,也可以没有抽象方法
//    public abstract void breath();
}

abstract class Person extends Creature{
    String name;
    int age;

    public Person(){
    }

    public Person(String name, int age){
        this.name = name;
        this.age = age;
    }

    public abstract void eat();//3.抽象方法只有方法的声明,没有方法体
}

//抽象类的子类:供实例化
class Student extends Person{
    public Student(){
    }
    
    public Student(String name, int age){
        this.name = name;
        this.age = age;
    }

    //必须要重写父类中的抽象方法
    @Override
    public void eat() {
        System.out.println("学生吃饭");
    }
}

3.3 多态性:抽象类的匿名子类

public class PersonTest {
    public static void main(String[] args) {
        //1. 匿名对象
        method(new Student());

        //非匿名的类 非匿名对象
        Worker worker = new Worker();
        method1(worker);

        method1(new Worker());//非匿名的类 匿名的对象

        //匿名子类的对象
        Person p = new Person() {//多态:子类对象赋给父类引用
            @Override
            public void eat() {
                System.out.println("匿名子类的对象: eat()");
            }
            @Override
            public void breath() {
                System.out.println("匿名子类的对象: breath()");
            }
        };
        method1(p);
        
        //匿名子类的匿名对象
        method1(new Person() {
            @Override
            public void eat() {
                System.out.println("匿名子类的匿名对象: eat()");
            }
            @Override
            public void breath() {
                System.out.println("匿名子类的匿名对象: breath()");
            }
        });
    }

    public static void method1(Person p){
        p.eat();
        p.breath();
    }

    public static void method(Student s){
    }
}

//1. 定义抽象类
abstract class Creature{
    //2. 定义抽象方法
    public abstract void breath();
}

abstract class Person extends Creature{
    String name;
    int age;

    public Person(){
    }

    public Person(String name, int age){
        this.name = name;
        this.age = age;
    }

    public abstract void eat();

    public void walk(){
        System.out.println("人走路");
    }
}

class Student extends Person{

    public Student() {
    }

    public Student(String name, int age) {
        super(name, age);
    }

    @Override
    public void breath() {
        System.out.println("学生呼吸");
    }

    @Override
    public void eat() {
        System.out.println("学生吃饭");
    }
}

class Worker extends Person{
    @Override
    public void breath() {
    }

    @Override
    public void eat() {
    }
}

3.4 模板方法

/**
 * 抽象类的应用:模板方法设计模式
 *      1. 抽象类:定义算法的骨架
 *      2. 实现类:实现特定步骤
 */

/*
 * 模板方法的理解:
 * 		1. 主要用途在于将不变的行为从子类搬到超类,去除了子类中的重复代码。
 * 		2. 模板方法模式(TemplateMethod),定义一个操作中的算法的骨架,而将一些步骤延迟到子类中,使得子类可以不改变一个算法的结构即可重定义该算法的某某些特定步骤
 *
 * 优缺点:
 *      封装不变部分,扩展可变部分
 *      提取公共部分代码,便于维护
 *      行为由父类控制,子类实现
 *      每一个不同的实现都需要一个子类实现,导致类的个数增加,使得系统更加庞大
 */

public class TemplateTest {

    public static void main(String[] args) {
        BankTemplateMethod btm1 = new DrawMoney();
        btm1.process();

        BankTemplateMethod btm2 = new ManageMoney();
        btm2.process();
    }
}

abstract class BankTemplateMethod{

    public void takeNumber(){
        System.out.println("排队取号");
    }

    public abstract void transact();//办理业务

    public void evaluate(){
        System.out.println("反馈评分");
    }

    // 模板方法,把基本操作组合到一起,子类一般不能重写
    public final void process(){
        this.takeNumber();
        this.transact();
        this.evaluate();
    }
}

class DrawMoney extends BankTemplateMethod{
    @Override
    public void transact() {
        System.out.println("我要取款");
    }
}

class ManageMoney extends BankTemplateMethod{
    @Override
    public void transact() {
        System.out.println("我要理财");
    }
}

4、接口

/* 
 * 1.接口使用interface来定义
 * 2.Java中,接口和类是并列的两个结构
 * 3.如何定义接口:定义接口中的成员
 *
 * 		3.1 JDK7及以前:只能定义全局常量和抽象方法
 * 			> 全局常量:public static final的. 但是书写时,可以省略不写
 * 			> 抽象方法:public abstract的
 *
 * 		3.2 JDK8:除了定义全局常量和抽象方法之外,还可以定义静态方法、默认方法
 *
 *      3.3 默认方法:只要把新添加(添加到接口中)的方法声明为default,实现类是默认继承该方法的
 *		3.4 接口中的静态方法只能通过接口来调用	
 *
 * 4. 接口中不能定义构造器,意味着接口不可以实例化
 *
 * 5. Java开发中,接口通过让类去实现(implements)的方式来使用.
 *    如果实现类覆盖了接口中的所有抽象方法,则此实现类就可以实例化
 *    如果实现类没有覆盖接口中所有的抽象方法,则此实现类仍为一个抽象类
 *
 * 6. Java类可以实现多个接口   --->弥补了Java单继承性的局限性
 *   格式:class AA extends BB implements CC,DD,EE
 *
 * 7. 接口与接口之间可以继承,而且可以多继承
 *
 * 8. 接口的具体使用,体现多态性
 * 9. 接口实际上可以看做是一种规范
 *
 * 面试题:抽象类与接口有哪些异同?
 */

public class InterfaceTest {
    public static void main(String[] args) {
        //全局常量可以通过类(接口).全局常量来调用
        System.out.println(Flyable.MAX_SPEED);
        //Flyable.MAX_SPEED = 3000;//error

        Plane plane = new Plane();
        plane.fly();
    }
}

interface Flyable{
    //全局常量
    public static final int MAX_SPEED = 7900;
    int MIN_SPEED = 1;//省略了public static final

    //抽象方法
    public abstract void fly();
    void stop();//省略了public abstract
}

interface Attackable{
    void attack();
}

class Plane implements Flyable{
    @Override
    public void fly() {
        System.out.println("通过引擎起飞");
    }

    @Override
    public void stop() {
        System.out.println("驾驶员减速停止");
    }
}

//没有完全重写父类/接口中的所有抽象方法,所以还是抽象类
abstract class Kites implements Flyable{
    @Override
    public void fly() {

    }
}

//实现类 可以实现多个接口,要重写所有接口中的抽象方法
class Bullet extends Object implements Flyable,Attackable,CC{

    @Override
    public void attack() {
        // TODO Auto-generated method stub

    }

    @Override
    public void fly() {
        // TODO Auto-generated method stub

    }

    @Override
    public void stop() {
        // TODO Auto-generated method stub

    }

    @Override
    public void method1() {
        // TODO Auto-generated method stub

    }

    @Override
    public void method2() {
        // TODO Auto-generated method stub

    }

}


interface AA{
    void method1();
}
interface BB{

    void method2();
}

//接口可以多继承
interface CC extends AA,BB{

}

4.1 多态性:接口的匿名子类

public class InterfaceTest1 {
    public static void main(String[] args) {
        Computer com = new Computer();

        Flash flash = new Flash();
        com.transferData(flash);

        com.transferData(new Printer());

        USB phone = new USB() {
            @Override
            public void start() {
                System.out.println("手机连接开始");
            }

            @Override
            public void stop() {
                System.out.println("手机停止连接");
            }
        };
        com.transferData(phone);

        com.transferData(new USB() {
            @Override
            public void start() {
                System.out.println("mp3开始连接");
            }

            @Override
            public void stop() {
                System.out.println("mp3停止连接");
            }
        });
    }
}


class Computer{
    //多态:
    // USB usb = new Flash();
    // USB usb = new Printer();
    public void transferData(USB usb){
        usb.start();

        System.out.println("传输数据");

        usb.stop();
    }
}

interface USB{

    //抽象方法,可以省略public abstract
    void start();

    void stop();
}

class Flash implements USB{

    @Override
    public void start() {
        System.out.println("U盘开始传输");
    }

    @Override
    public void stop() {
        System.out.println("U盘停止传输");
    }
}

class Printer implements USB{
    @Override
    public void start() {
        System.out.println("打印机开始打印");
    }

    @Override
    public void stop() {
        System.out.println("打印机停止打印");
    }
}

5、关键字

6-4关键字.png

1. static

可以修饰属性、方法、代码块、内部类

1.1 static修饰属性

  • 静态属性/类变量:类的多个对象共享同一个静态变量

    • 当通过某一个对象修改静态变量时,会导致其他对象调用此静态变量时,是修改过的
    • 随着类的加载而加载,可以通过"类.属性"的方式调用
    • 静态变量的加载早于对象的创建
    • 由于类只会加载一次,所以静态变量在内存中也会只存在一份,存在方法区2的静态域中
  • 非静态属性/实例变量

静态变量和实例变量.jpg

1.2 static修饰方法

  • 随着类的加载而加载,可以通过"类.静态方法"的方式进行调用
  • 静态方法中,只能调用静态的方法或属性
  • 非静态方法中,既可以调用非静态的方法或属性,也可以调用静态的方法或属性
  • 在静态的方法内,不能使用this关键字、super关键字

2. final

可以用来修饰类、方法、变量

  • final修饰的类:不可被继承
  • final修饰的方法:不可被重写
  • final修饰局部变量:常量或者说不可变变量,存储在栈中
  • final修饰属性:常量,在类编译时期载入类的常量池中
    • 初始化赋值
    • 代码块中初始化赋值
    • 构造器中初始化赋值
  • static final修饰属性:全局常量
    • 可以在静态代码块中初始化
    • 可以通过类.属性调用
public class FinalTest {

	//1. final修饰属性:常量,在类编译时期载入类的常量池中
	//1.1 初始化赋值
	final int WIDTH = 0;
	final int LEFT;
	final int RIGHT;
    //static fianl修饰属性
    static final int DOWN;

	static {
		DOWN = 3;
	}
	
    //1.2 代码块中初始化赋值
	{
		LEFT = 1;
	}
	
    //1.3 构造器中初始化赋值
	public FinalTest(){
		RIGHT = 2;
	}
	
	public FinalTest(int n){
		RIGHT = n;
	}

	//final修饰属性:常量,初始化后不可被修改
	public void doLeft(){
		LEFT = 20;//error
	}
	
    //2. final修饰局部变量:常量,不可修改
	public void show(){
		final int NUM = 10;//常量
//		NUM += 20;
	}
	public void show(final int num){
//		num = 20;//编译不通过
		System.out.println(num);
	}
}

3. this

  • this理解为:当前对象 或 当前正在创建的对象

  • 可以修饰属性、方法、构造器

3.1 this调用属性和方法

在类的方法中,我们可以使用"this.属性"或"this.方法"的方式,调用当前对象属性或方法。通常情况下,我们都选择省略"this."。特殊情况下,如果方法的形参和类的属性同名时,我们必须显式的使用"this.变量"的方式,表明此变量是属性,而非形参

在类的构造器中,我们可以使用"this.属性"或"this.方法"的方式,调用当前正在创建的对象属性或方法。通常情况下,我们都选择省略"this."。特殊情况下,如果构造器的形参和类的属性同名时,我们必须显式的用"this.变量"的方式,表明此变量是属性,而非形参

3.2 构造器中使用this

  • 我们在类的构造器中,可以显式的使用"this(形参列表)"方式,调用本类中指定的其他构造器
  • 构造器中不能通过"this(形参列表)"方式调用自己
  • 规定:"this(形参列表)"必须声明在当前构造器的首行
  • 构造器内部,最多只能声明一个"this(形参列表)",用来调用其他的构造器

4. super

  • super理解为:父类的
  • super可以用来调用:属性、方法、构造器

4.1 super调用属性和方法

我们可以在子类的方法或构造器中。通过使用"super.属性"或"super.方法"的方式,显式的调用父类中声明的属性或方法。通常情况下,我们习惯省略"super."

  • 特殊情况:当子类和父类中定义了同名的属性时,我们要想在子类中调用父类中声明的属性,则必须显式的使用"super.属性"的方式,表明调用的是父类中声明的属性。
  • 特殊情况:当子类重写了父类中的方法以后,我们想在子类的方法中调用父类中被重写的方法时,则必须显式的使用"super.方法"的方式,表明调用的是父类中被重写的方法。

4.2 super调用构造器

可以在子类的构造器中显式的使用"super(形参列表)"的方式,调用父类中声明的指定的构造器

  • "super(形参列表)"的使用,必须声明在子类构造器的首行!
  • 在类的构造器中,针对于"this(形参列表)"或"super(形参列表)"只能二选一,不能同时出现
  • 在构造器的首行,没有显式的声明"this(形参列表)"或"super(形参列表)",则默认调用的是父类中空参的构造器:super()
  • 在类的多个构造器中,至少有一个类的构造器中使用了"super(形参列表)",调用父类中的构造器