JAVA常见关键字及JDK 常用方法源码分析(持续更新...)
一、JAVA常见关键字
1、this
1)、常用于指向当前类对象本身(指向当前对象的本身),具体实现代码如下:
public class Student {
private String name = "默认值1";
public Student(){
System.out.println("姓名:"+name);
}
public String getName(String name){
this.name = name;
return this.name;
}
}
public class Main1 {
public static void main(String[] args) {
Student student = new Student();
String name = student.getName("张三");
System.out.println("返回结果:"+name);
}
}
姓名:默认值1
返回结果:张三
Process finished with exit code 0
this.name 指向的是private 定义的成员变量name,而不是形参name
2)、this 调用本类构造函数,代码如下:
public class Student {
private String name = "默认值1";
public Student(String name){
System.out.println("姓名:"+name);
}
public Student(String name, int age){
this(name);//调用具有相同形参的构造方法
System.out.println("年纪:"+age);
}
public String getName(String name){
this.name = name;
return this.name;
}
}
public class Main1 {
public static void main(String[] args) {
Student student = new Student("李四", 20);
String name = student.getName("张三");
System.out.println("返回结果:"+name);
}
}
姓名:李四
年纪:20
返回结果:张三
Process finished with exit code 0
this另外一个作用就是调用本类中构造函数(同super,后续再讲)
另外,this只能在类中的非静态方法中使用,静态方法和静态的代码块中绝对不能出现this。
2、super
调用父类构造函数,代码如下:
父类:
public class Class1 {
public Class1(){
System.out.println("父类无参构造函数C");
}
public Class1(String cname){
System.out.println("班级是:"+cname);
}
}
子类:
public class Teacher1 extends Class1{
public Teacher1(){
super();
System.out.println("调用父类无参构造函数成功T");
}
public Teacher1(String cname){
super(cname);
System.out.println("调用父类有参构造函数成功K");
}
}
public class Main1 {
public static void main(String[] args) {
Teacher1 teacher1 = new Teacher1();
Teacher1 teacher2 = new Teacher1("精英班");
}
}
结果:
父类无参构造函数C
调用父类无参构造函数成功T
班级是:精英班
调用父类有参构造函数成功K
Process finished with exit code 0
可以看出,super可实现调用父类的无参或有参构造函数
super和this的异同:
- super(参数):调用基类中的某一个构造函数(应该为构造函数中的第一条语句)
- this(参数):调用本类中另一种形成的构造函数(应该为构造函数中的第一条语句)
- super: 它引用当前对象的直接父类中的成员(用来访问直接父类中被隐藏的父类中成员数据或函数,基类与派生类中有相同成员定义时如:super.变量名 super.成员函数据名(实参)
- this:它代表当前对象名(在程序中易产生二义性之处,应使用this来指明当前对象;如果函数的形参与类中的成员数据同名,这时需用this来指明成员变量名)
- 调用super()必须写在子类构造方法的第一行,否则编译不通过。每个子类构造方法的第一条语句,都是隐含地调用super(),如果父类没有这种形式的构造函数,那么在编译的时候就会报错。
- super()和this()类似,区别是,super()从子类中调用父类的构造方法,this()在同一类内调用其它方法。
- super()和this()均需放在构造方法内第一行。
- 尽管可以用this调用一个构造器,但却不能调用两个。
- this和super不能同时出现在一个构造函数里面,因为this必然会调用其它的构造函数,其它的构造函数必然也会有super语句的存在,所以在同一个构造函数里面有相同的语句,就失去了语句的意义,编译器也不会通过。
- this()和super()都指的是对象,所以,均不可以在static环境中使用。包括:static变量,static方法,static语句块。
- 从本质上讲,this是一个指向本对象的指针, 然而super是一个Java关键字。
3、final 最终、不可变
final在Java中是一个保留的关键字,可以声明成员变量、方法、类以及本地变量。一旦你将引用声明作final,你将不能改变 这个引用了,编译器会检查代码,如果你试图将变量再次初始化的话,编译器会报编译错误。例子如下:
1)、修饰变量,变量不可改变
提示:Cannot assign a value to final variable 'i' :不能为最终变量'i'赋值。被final修饰的变量初始值是什么,调用时不能重新赋值。
2)、修饰方法,不能被子类重写
Class1 父类final 修饰的方法ftest() 不能被override重写。
3)、修饰类,类不可被继承
final 修饰的类不能被继承。
网上也有这样解释不可变,挺有道理:如果一个对象,在它创建完成之后,不能再改变它的状态,那么这个对象就是不可变的。不能改变状态的意思是,不能改变对象内的成员变量,包括基本数据类型的值不能改变,引用类型的变量不能指向其他的对象,引用类型指向的对象的状态也不能改变。
二、JDK 常用方法源码分析
1、String 源码分析
谈到String,最长想到的是String 赋值后不可变,即变量不可变,这时肯定能想到上文中提到的final修饰的变量不可变原理。
创建一个String对象,查看源码可知,String类确实是被final修饰了。
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
/** The value is used for character storage. */
private final char value[];
/** Cache the hash code for the string */
private int hash; // Default to 0
/** use serialVersionUID from JDK 1.0.2 for interoperability */
private static final long serialVersionUID = -6849794470754667710L;
可以发现,String类被final修饰,导致不可被继承。细心的同学会发现,同样final还修饰了一个字符数组变量 value[],Java中的String其实就是对字符数组的封装,所以导致String 创建后是不可变的,至于为什么要设计为不可变,那就涉及到内存、同步、数据结构相关方面知识。简单分析:
先看这张图,当创建一个字符串对象时,如果字符串值已经存在于常量池里面,则不会再创建一个新的对象,而是引用已经存在的对象,也就是以下情况时。
String st1 = "abcd";
String st2 = "abcd";
这里涉及到一个字符串常量池稍作解释:
字符串常量池是java堆内存中一个特殊的存储区域,JVM(java 虚拟机)为了提高性能和减少内存开销,在实例化字符串常量时进行了一些优化,单独开辟一个字符串常量池,创建字符串常量时,首先判断字符串常量池是否存在该字符串,如果有则直接返回引用实例,不存在,则该字符串放在常量池中。
要实现字符串常量池的前提是,必须保证字符串不可变,不然数据共享时就会产生冲突。 同样,字符串的不可变保证了对应的hashcode永远不变,每次在使用一个字符串的hashcode的时候就不需要重新计算一次,提高了效率。
/** Cache the hash code for the string */
private int hash; // Default to 0
(译:缓存字符串的散列码)
另外,不可变对象是线程安全的,多个线程共享时,无需做同步处理
总结来讲,String 设计成不可变,提高了效率和安全性
下面再调试看看String 究竟是如何赋值的: