九、关键字(this、super)
9.1、this关键字
this
关键字表示当前对象(谁调用this所在的方法,this就是哪一个对象主要)存在于两个位置:
- 在构造器中:表示当前创建的对象
- 在方法中:哪一个对象调用this所在的方法,此时this就表示哪个对象
什么时候需要使用this关键字
- 为了解决局部变量和成员变量之间的二义性,此时必须使用
- 同一个类中非static方法之间的互相调用,此时可以省略,但是基本不会省略
- 调用本类其他的构造方法
public class Dog { private String name; private int age; public Dog() { } public Dog(String name) { this(name, 0);// 调用两个参数的构造器(构造器之间的重载),必须放在构造器第一行 } public Dog(String name, int age) { this.name = name; this.age = age; } public void say() { String name = "局部变量"; System.out.println(name); // 访问局部变量 System.out.println(this.name);// 访问成员变量 this.other();// 调用当前类中非static方法 } public void other() { System.out.println(this.age);//此时的this是谁 } } 复制代码
this内存图
this关键字表示当前对象本身,一般用于类的内部,其内部存在一个地址,指向当前初始化对象本身
当new一个对象的时候,实际上产生了两个引用,一个是供Dog内部调用其他成员变量或者成员方法的this关键字,另一个是供外界程序调用实例成员的dog持有类信息
9.2、super关键字
super表示当前对象的父类对象,在创建子类对象的时候,在子类构造器的第一行会先调用父类的构造器
super虽然表示父类对象,但是他仅仅只是一个关键字,内部并没有地址,所以不能够引用
什么时候使用super
- 访问父类中非私有的实例方法,此时必须使用super
- 在子类的构造器中,调用父类的构造器,此时必须使用super
- 如果想访问父类的非私有成员变量,此时必须使用super
父类:
public class Person { private String name; private int age; public Person() { } public Person(String name, int age) { this.name = name; this.age = age; } public void doWork() { System.out.println("Person...doWork..."); } } 复制代码
子类:
public class Student extends Person { private String sn; public Student(String sn) { super();// 隐式调用父类无参数构造器,必须作为构造第一行 this.sn = sn; } public Student(String name, int age, String sn) { super(name, age);// 显示去调用父类有参数构造器,必须作为构造第一行 this.sn = sn; } public void doWork() { super.doWork(); // 此时调用父类的doWork()方法 this.doWork(); // 此时调用自己的doWork()方法 System.out.println("Student...doWork..."); } } 复制代码
总结
- super调用构造方法必须写在子类构造方法的第一行
- 如果子类构造方法没有显示调用父类构造方法时,那么JVM会默认调用父类的无参构造器
十、修饰符(static、final)
10.1、static修饰符
static修饰的字段和方法都直接属于类,不属于该类的对象(字段和方法属于谁,就让谁来调用)
- 有static修饰的变量和方法:属于类,直接用类名调用即可,在同一个类中调用可以省略类名不写
- 没有static修饰的变量和方法:属于对象,必须先创建对象,然后用对象调用
注意:static方法不能使用super和this关键字
因为static是类级别的,super和this是对象级别的,存在类的时候不一定存在对象,也就说使用类名调用static方法时,此时可能是没有对象的。 复制代码
10.1.1、静态方法
static修饰的方法称为静态方法,归类所有,也称为类方法
修饰符 static 返回值类型 方法名(形参列表){ } 复制代码
静态方法有两种访问方式:
- 类名.静态方法名()√
- 对象.静态方法名()Java是不推荐这种访问机制的
静态方法的特性
- 静态方法中可以访问静态变量和其他静态方法
- 实例方法中可以访问静态成员变量以及静态成员方法
10.1.2、静态变量
在类中,用static关键字修饰的成员变量称为静态变量,归类所有,也称为类变量,类的所有实例对象都可以访问,被类的所有实例或者对象共享
static 数据类型 成员变量 复制代码
静态变量的访问
- 类名.静态变量
- 类的对象.静态变量(Java不推荐)
10.2、final修饰符
final的含义是最终的,不可改变的,可以修饰类、方法、变量,他是来限制某个类不可以有子类,不可以覆盖方法
final修饰的类
表示最终的类,该类不可以再拥有子类
final public class Super { } public class Sub extends Super{ //此行语法报错 } 复制代码
final修饰的方法
最终的方法,该方法不可以被子类覆盖
public class Super { final public void doWork() { } } public class Sub extends Super{ public void doWork() { //此行语法报错 } } 复制代码
final修饰的变量
表示常量,该变量只能赋值一次,不可以再重新赋值
- 基本数据类型:表示的值不能再改变
- 引用数据类型:所引用的地址不可以再改变
final int age = 17; age = 100; //此行语法报错 final Dog d = new Dog(); d.setAge(5); //d的字段值是可以改变的 d = new Dog(); //此行语法报错 复制代码
十一、代码块
直接使用{}括起来的一段代码区域,代码块里面的变量属于局部变量,仅在{}内有效
他有三种存在形式:普通代码块、构造代码块、静态代码块
11.1、普通代码块
直接定义在方法内部的代码块,一般的,不会直接使用局部代码块的,结合if、while、for等关键字使用,表示一块代码区域,作用域可以嵌套
public class CodeBlockDemo { public static void main(String[] args) { System.out.println("begin..."); { //直接使用代码块,一般不用 int age = 17; } System.out.println(age); //此行报错,超出age作用范围,就不能访问到了 if (100 > 5) { System.out.println("100 > 5"); } System.out.println("end..."); } } 复制代码
11.2、构造代码块
构造代码块在类的内部,方法的外部,随着一个对象的创建而执行一次,在构造方法前执行
package day09_ObjectAdvanced.Classing.StaticBlock; /** * @author Xiao_Lin * @version 1.0 * @date 2020/12/9 16:29 */ public class Dog { private String name; static String age="111"; { System.out.println("我是构造代码块"); } public Dog(){ System.out.println("我是无参构造方法"); } public Dog(String name){ System.out.println("我是有参构造方法"); } public void shut(){ System.out.println("我是叫方法"); } } 复制代码
如果需要在构造方法执行前加载一些资源(如读配置文件、XML文件等等),我们可以把构造对象前的一切操作都放在构造代码块中执行
11.3、静态代码块
用static关键字所修饰的代码块称为静态代码块,位于类的内部、方法的外部,且只执行一次,在构造代码块、构造方法前执行
package day09_ObjectAdvanced.Classing.StaticBlock; /** * @author Xiao_Lin * @version 1.0 * @date 2020/12/9 16:29 */ public class Dog { private String name; static String age="111"; static { System.out.println("我是静态代码块"); } { System.out.println("我是构造代码块"); } public Dog(){ System.out.println("我是无参构造方法"); } public Dog(String name){ System.out.println("我是有参构造方法"); } public void shut(){ System.out.println("我是叫方法"); } } 复制代码
十二、内部类
12.1、类的组织方式
12.1.1、类和类的平行关系
一个文件可以定义多个类,但只能存在一个public类,且文件的名字和public类的名字要保持一致
public class Dog{ } class Cat{ } 复制代码
Dog和Cat地位一样,和分开定义两个文件是一模一样的
12.1.2、类和类之间包含关系
public class Outer { public class Inner{ } } 复制代码
Outer和Inner是包含关系,Outer称为外部类,而Inner称为内部类,内部类Inner作为一个Outer的成员而存在
12.2、内部类的概述
什么是内部类,把一个类定义在另一个类的内部,把里面的类称之为内部类,把外面的类称之为外部类,内部类的分类有:
- 成员内部类
- 静态内部类
- 方法内部类
- 匿名内部类
12.3、匿名内部类
当一个类只使用一次,可以声明成匿名内部类
匿名内部类 必须有实现存在,多以实现接口居多
public class Outer { public void print(){ /* class Inner implements AInterface{ @Override public void showInfo() { System.out.println("inner.showInfo"); } } new Inner().showInfo(); */ /* AInterface aInterface = new AInterface(){ @Override public void showInfo() { System.out.println("inner.showInfo"); } }; aInterface.showInfo(); */ // 通过匿名类创建匿名对象 new AInterface(){ @Override public void showInfo() { System.out.println("inner.showInfo"); } }.showInfo(); } } 复制代码
十三、枚举类
枚举是一种特殊的类,固定一个类只能有哪些对象
13.1、枚举类的定义
public enum 枚举类型{ 常量对象A、常量对象B、常量对象C } 复制代码
publicc enum Story{ HISTORY、ENGLISH、MATH } 复制代码
我们自定义的枚举类都是在底层直接继承了 java.lang.Enum
类,枚举中都是全局公共的静态常量,可以直接用枚举类名调用
Stroy story = Story.ENGLISH; 复制代码
因为java.lang.Enum类是所有枚举类的父类,所以所有的枚举对象可以调用Enum类中的方法
String name = 枚举对象.name(); // 返回枚举对象的常量名称 int ordinal = 枚举对象.ordinal(); // 返回枚举对象的序号,从0开始 复制代码
注意:枚举类不能使用创建对象