This关键字
this 内存图
this关键字表示当前对象本身,一般用于类的内部,其内部存在一个地址,指向当前初始化的对象本身。
当new一个对象时,实际上产生了两个引用,一个是供类Dog内部调用其成员变量和成员方法的this关键字,一个是供外界程序调用实例成员的dog。
this 三种用法
什么时候需要使用this:
调用成员变量
解决局部变量和成员变量之间的二义性,此时必须使用
调用其他成员方法
同一个类中非static方法间互调(此时可以省略this,但是不建议省略)
- 调用本类其他构造方法(掌握)
this可以调用本类其他构造方法
注意 : 在构造方法中调用本类其他构造方法必须写到该构造方法第一句,否则出现编译错误。
一个结合this,满足封装的实战中的Dog类。
public class Dog { private String id; private String name; private int age;
public Dog(String id ,String name) { this.id = id;
this.name = name;
}
public Dog(String id, String name, int age) {
// this.id = id;
// this.name = name;
// 其他构造器的调用必须写在本构造器中第一句
this(id, name); this.age = age;
}
public Dog() { }
// 省略设置器和访问器
public void showInfo(){ System.out.println("id:" + this.id); System.out.println("名字:" + this.name); System.out.println("年龄:" + this.age);
}
public void sayHi() {
System.out.println("大家好,以下是我的信息:"); this.showInfo();
}
}
super关键字
在子类方法中,调用父类被覆盖的方法,此时必须使用super
super 关键字表示父类对象,子类要访问父类成员时一定要使用super。
super只是一个关键字,内部没有引用(地址)。
- super 访问父类非私有字段
- super 访问父类非私有方法
- super 访问父类构造方法
注意 :
super 调用构造方法必须写在子类构造方法的第一句。
如果子类构造方法没有显式调用父类任何构造方法时,那么jvm会默认调用父类的无参构造super()
static 修饰符
需求 + 问题:
构成一个车(Car) 的类,统计Car一共创建了多少对象?
=> 紧接着继续思考:统计Car创建了多少对象是不是需要一个变量totalCount?
=> 紧接着继续思考:在哪里声明这个变量totalCount呢?
static 关键字表示静态,可以修饰成员变量构成静态变量,修饰成员方法构成静态方法。静态变量和静态方法都归类所有,称为类的静态成员,用static关键字修饰
静态变量
在类中,用static关键字修饰的成员变量称为静态变量,归类所有,也称为类变量,类的所有实例/对象都可以访问,被类的所有实例或对象所共享。
语法 :
静态变量的访问
思考:为什么通过实例可以访问静态成员?=> 类变量/静态变量被类的所有实例或对象所共享!
静态方法
static 也可以修饰方法称为静态方法,归类所有,也称类方法。形式
静态方法访问方式
静态变量和静态方法称为类的静态成员,归类所有,成员变量和成员方法称为类的实例成员,归对象所有。
静态方法特性
静态方法中只能访问类的静态成员,不能访问实例成员
实例方法中可以访问类的静态成员
1.3.4 jvm加载 static 成员的过程(理解)
当加载一个类到jvm的方法区时,首先jvm会扫描xx.class中的静态成员并分配空间且初始化。
当通过xx.class new一个对象时,可以在该对象的实例方法中访问静态成员;反之静态方法中不能访问实例成员。
final修饰符
final 表示最终的意思,可以修饰类、方法、局部变量,甚至可以修饰成员变量。
最终类
final 修饰类表示最终类。
最终类不能被继承
最终方法
如果一个方法被final修饰,称为最终方法。
最终方法不能被重写
常量
final修饰的局部变量称为常量,常量只能赋值一次,不能再重新赋值。
基本数据类型:表示的值不能改变
引用数据类型:所引用的地址值不能改变
代码块
{ } 标记的代码称为代码块,根据其位置的不同可以分为普通代码块、构造代码块、静态代码块、同步代码块
普通代码块
普通代码块{ },也成局部代码块,一般存在于方法中,形成作用域。
作用域特性:
[1].作用域可以嵌套,内层作用作用域可以访问外层作用域的变量
[2].当访问一个变量时,首先在变量所在的作用域查找,如果能找到,停止查找并输出变量内容;当本作用域没找到时,尝试去上一层作用域查找,依次类推。这个过程形成的查找链称为作用域链。
构造代码块
构造代码块在类中(类的内部)、方法外,也称为初始化代码块。构造代码块构造一个对象执行一次,在构造方法前执行。
开发中不使用初始化代码块,即使要做初始化操作,可以直接在构造器中完成即可。
静态代码块
被static关键字修饰的代码块称为静态代码块。静态代码块位于类的内部、方法的外部。
静态代码块只执行一次(jvm加载xx.class时执行),在构造代码块、构造方法前执行。
当类的字节码被加载到内存时,此时程序需要加载一些资源(读取资源文件、读取配置文件等),可以使用静态代码块,此时被加载进来的资源一般都可以被多个实例所共享。
内部类
内部类概述
什么是内部类,把一个类定义在另一个类的内部,把里面的类称之为内部类,把外面的类称之为外部类。
内部类可以看作和字段、方法一样,是外部类的成员,而且成员可以有static修饰。
静态内部类:使用static修饰的内部类,那么访问内部类直接使用外部类名来访问
实例(成员)内部类:没有使用static修饰的内部类,访问内部类使用外部类的对象来访问
局部(方法)内部类:定义在方法中的内部类,一般不用
匿名内部类:特殊的局部内部类,适合于仅使用一次使用的类
对于每个内部类来说,Java编译器会生成独立.class文件。
静态和实例内部类:外部类名$内部类名字
局部内部类:外部类名$数字内部类名称
匿名内部类:外部类名$数字
匿名内部类
思考1:为什么我们要显示声明一个Student类?
当一个类只使用一次,可以声明成匿名内部类。匿名内部类 必须有 实现 存在。匿名内部类,可以使用父类构造器和接口名来完成。
针对类,定义匿名内部类来继承父类(使用较少):
针对接口,定义匿名内部类来实现接口(使用较多):
注意:这里不是根据 父类/接口 创建对象,而是一种语法而已综合案例 : 使用匿名内部类
枚举类
在服装行业,衣服的分类根据性别可以表示为三种情况:男装、女装、中性服装。
需求:定义一个变量来表示服装的分类?请问该变量的类型使用什么?
使用int和String类型,且先假设使用int类型,因为分类情况是固定的,为了防止调用者乱创建类型,可以把三种情况使用常量来表示。
注意:常量使用final修饰,并且使用大写字母组成,如果是多个单词组成,使用下划线分割。
此时调用setType方法传递的值应该是ClothType类中三个常量之一。但是此时依然存在一个问题——依然可以乱传入参数比如100,此时就不合理了。
同理如果使用String类型,还是可以乱设置数据。那么说明使用int或String是类型不安全的。那么如果使用对象来表示三种情况呢?
此时调用setType确实只能传入ClothType类型的对象,但是依然不安全,为什么?因为调用者可以自行创建一个ClothType对象,如:setType(new ClothType())。
此时为了防止调用者私自创建出新的对象,我们把CLothType的构造器私有化起来,外界就访问不了了,此时调用setType方法只能传入ClothType类中的三个常量。此时代码变成:
高,实在是高!就是代码复杂了点,如果存在定义这种类型安全的且对象数量固定的类的语法,再简单点就更好了——有枚举类。
枚举类的定义和使用
枚举是一种特殊的类,专门用于声明可罗列的常量值,定义格式:
我们自定义的枚举类在底层都是直接继承了java.lang.Enum类的。
枚举中都是全局公共的静态常量,可以直接使用枚举类名调用。
因为java.lang.Enum类是所有枚举类的父类,所以所有的枚举对象可以调用Enum类中的方法.
int ordinal = 枚举对象.ordinal(); // 返回枚举对象的序号,从0开始注意:枚举类不能使用创建对象