笔记来自2019求知讲堂零基础Java入门编程视频教程 https://www.bilibili.com/video/av76235341
this关键字
this表示当前对象,其本质就是“创建好的对象的地址”,可以使用this调用类的属性,方法和构造器。当在方法内需要调用到该方法的对象时,就需要用到this关键字
它在方法内部使用,即这个方法所属对象的引用
它在构造方法内部使用,表示该构造方法正在初始化的对象
举个最常用的例子,构造方法中以及set方法中使用this
public class Person {
public Person(int age) {
//this.age = age;
age = age;
}
private int age;
public void setAge(int age){
//this.age = age;
age = age;
}
}
public class Test {
public static void main(String[] args) {
Person p = new Person(2);
p.setAge(5);
p.printAge();
}
}
//运行结果:年龄是:0
上面两个方法中," this.age = age; "的地方如果直接使用age = age,系统会默认age是形参,那么这个等式是无用的,因为它没有意义,系统会报警示:The assignment to variable age has no effect,实际运行也会发现,无论是使用构造方法还是使用setAge方法为age赋值,都是不生效的。
this还可以作为一个类中,构造器互相调用的特殊格式,依旧举一个例子:
Person类中有两个成员变量age和name,以及两个构造方法,其中一个调用了另一个来给age做初始化。
public class Person {
public Person(int age) {
this.age = age;
}
public Person(String name) {
this(18); //等同于调用public Person(int age)
this.name = name;
}
private int age;
private String name;
public void printInfo() {
System.out.print("年龄是:" + age);
System.out.println(" 姓名是:" + name);
}
}
//运行结果:年龄是:18 姓名是:zhixiao
综上,总结this的三个使用场景
①当方法的形参与成员变量重名时,如果在方法内部需要使用成员变量,必须添加this来表明该变量是类成员,否则系统会默认为是形参。(必须加this)
②this还可以作为一个类中,构造器互相调用的特殊格式,此时this()必须在构造器的第一行,且不能出现构造器自己调用自己的情况(包括A调用B,B调用A这种情况)。
③在任意方法中,如果使用当前类的成员变量或成员方法时,可以在其前面加上this,以增强程序的阅读性。(可加可不加,但最好是加上)
super关键字
super关键字用于调用父类中的指定操作,尤其当父类子类出现同名成员,可以用super加以区分。
- 可以用于访问父类中定义的属性和方法,且不仅限于直接父类
//Graduated类继承Student类,Student类继承Person类
public class Graduated extends Student{
public void test() {
//可以使用super直接追溯父类的属性方法
super.school = "北大青鸟"; //Student类的School属性
super.getSchool(); //Student类的getSchool()方法
//使用super可以向上追溯到父类的父类
super.age = 1; //调用Person类的age属性
super.getAge(); //调用Person类的getAge()方法
}
}
- 可以在子类构造器中调用父类的构造器
没有显式声明的情况下,子类的构造器会默认访问父类中的空参数构造器。
//Person类中只写一个无参构造,方法内输出文字
public class Person {
public Person() {
System.out.println("Person类的无参构造");
}
}
//Student类什么都不写
//Test类中只new一个Student对象
public class Test {
public static void main(String[] args) {
Student stu = new Student();
}
}
//运行结果:Person类的无参构造
//同理,多层继承情况下下,new一个Graduated对象,输出的也是Person类的无参构造
可以看出创建子类对象的时候,实际上调用了父类的空参数构造器。
当父类中没有空参数构造器时,子类的构造器必须通过this(参数列表)或者super(参数列表)语句指定调用本类或者父类中相应的构造器,且必须放在构造器第一行。
我们先将Person类中的无参构造换成有参构造:
//Person类中定义一个有参构造
public class Person {
public Person(int age) {
this.age = age ;
}
int age;
}
此时Student类报错:Implicit super constructor Person() is undefined for default constructor. Must define an explicit constructor。提示隐式的无参构造不是默认的构造器,需要自己定义一个有参的构造器。
public class Student extends Person{
public Student(int age) {
super(age);
}
}
this和super的区别
this | super | |
---|---|---|
访问属性 | 访问本类中的属性,若本类中没有此属性则从父类中继续查找 | 访问父类中的属性 |
调用方法 | 访问本类中的方法,若本类中没有则从父类中继续查找 | 访问父类中的方法 |
调用构造器 | 调用本类构造器,必须放在构造器首行 | 调用父类构造器,必须放在子类构造器首行 |
特殊 | 表示当前对象 | 无 |
关键字static
当我们编写一个类的时候,其实是在描述其对象的属性和行为,并没有产生实质上的对象。只有通过new关键字才会产生新的对象,并在内存中分配空间,然后才能使用访问这个类的属性和方法。
如果我们想不论类有没有被实例化,都可以使用这个类的属性和方法,就需要把方法和属性设置为static(静态)的。
这样的属性在内存空间里只有一份,被所有实例化对象所共享,称为类变量(或静态变量),是类的一部分,可以直接用类名.属性访问。(而普通的实例变量,是属于实例化对象的一部分,只有实例化才能够使用。)
public class Person {
static int i;
}
public class Test2 {
public static void main(String[] args) {
Person.i = 1;//直接使用 类名.属性 为静态变量赋值
Person p1 = new Person();
System.out.println(p1.i++); //输出结果:1
Person p2 = new Person();
System.out.println(p1.i++); //输出结果:2
Person p3 = new Person();
System.out.println(p1.i++); //输出结果:3
//体现静态变量是所有对象共享的
}
}
同理,也可以设计类方法(静态方法),如果方法与调用者无关,不需要因为对象的不同而频繁的new对象来调用,就可以把这样的方法设置成类方法,可以不声明对象直接用 类名.方法名 调用。(一般做工具类比较常用,当一个操作需要反复执行,就可以把它写成工具类,比如判断一个字符串是否为空。)
//写一个工具类,一个判断字符串是否为空的静态方法
public class Utils {
public static boolean isEmptyStr(String s) {
boolean flag = false;
if (s != null && !s.equals("")) {
flag = true;
}
return flag;
}
}
public class Test2 {
public static void main(String[] args) {
System.out.println(Utils.isEmptyStr("12")); //true
System.out.println(Utils.isEmptyStr("")); //false
System.out.println(Utils.isEmptyStr(null)); //true
}
}
根据之前介绍的JVM内存模型理解,static的数据是放在方法区的,class文件加载的同时就一并加载了,所以不需要创建对象就可以使用,而非static的属性方法是在new的时候才放入堆内存中的。
需要格外注意的是:
- static方法内不能有this和super关键字
- 重载的方法必须同时是static或同时为非static的
关键字final
可以用来修饰类、属性、方法时,表示最终。
- final标记的类不能被继承。
- final标记的方法不能被子类重写。
- final标记的变量(成员变量或局部变量)即为常量,只能被赋值一次,名称全大写。(final标记的成员变量必须在声明的同时或在每个构造方法中或代码块中显示赋值,才能被使用。)
- static final 修饰——全局常量