this关键字
this关键字的主要用途:
1.this调用本类属性
2.this调用本类方法
3.this表示当前对象
this调用本类属性
代码:
class Person{
private String name;
private int age;
public Person(String name,int age){
this.name = name; //使用this调用本类的属性name
this.age = age; //使用this调用本类的属性age
/*
有人可能觉得this不一定要使用,但是在这里形参和属性重名,为了区分
使用this调用就表示是本类的属性,可以进行赋值。否则形参与类中的属性同名时
类中属性无法被正确赋值。
*/
}
public String getPersonInfo(){
return "姓名:" + name + ",年龄:" + age;
}
}
public class Test{
public static void main(String[] args) {
Person person = new Person("abaka",21);
System.out.println(person.getPersonInfo());
}
}
this调用本类方法
在这里this 调用本类方法有两种情况:
1.调用普通方法:this.方法名称(参数)
2.调用构造方法:this(参数)
this调用普通方法:
class Person{
private String name;
private int age;
public Person(String name,int age){
this.name = name;
this.age = age;
this.getPersonInfo();
/*
this调用普通方法,这里可以不使用this进行调用,但是推荐加上,
加上可以区分方法的定义来源,在继承中会使用到。
*/
}
public void getPersonInfo(){
System.out.println("姓名:" + name + ",年龄:" + age);
}
}
public class Test{
public static void main(String[] args) {
Person person = new Person("abaka",21);
}
}
this调用构造方法:
class Person{
private String name;
private int age;
public Person(){
System.out.println("1.**********************");
}
public Person(String name){
this();
/*
this()调用本类的Person()方法。
*/
System.out.println("2.**********************");
this.name = name;
}
public Person(String name,int age){
this(name);
/*
this(name)调用本类的Person(String name)方法
*/
System.out.println("3.**********************");
this.age = age;
this.getPersonInfo();
}
public void getPersonInfo(){
System.out.println("姓名:" + name + ",年龄:" + age);
}
}
public class Test{
public static void main(String[] args) {
Person person = new Person("abaka",21);
}
}
运行结果:
1.**********************
2.**********************
3.**********************
姓名:abaka,年龄:21
在java中支持构造方法的相互调用,
使用this调用构造方法时请注意:
1.this调用构造方法的语句必须在方法的首行,否则会报错(受查异常)
2.使用this调用构造方法时,要留出口。不能在调用构造中成环,这样就是死循环。
this表示当前对象
class Person{
private String name;
private int age;
public void print(){
System.out.println("print方法:" + this);//this调用当前类的对象
}
}
public class Test{
public static void main(String[] args) {
Person person1 = new Person();
System.out.println("main方法:"+ person1);
person1.print();
System.out.println("----------------------");
Person person2 = new Person();
System.out.println("main方法:"+ person2);
person2.print();
}
}
运行结果:
main方法:www.bit.java.Person@1540e19d
print方法:www.bit.java.Person@1540e19d
----------------------
main方法:www.bit.java.Person@677327b6
print方法:www.bit.java.Person@677327b6
结果中print方法和main方法显示的地址是一样的,那是因为print方法中调用了this,打印的是当前类的对象,而main是直接打印除了当前对象,所以两个是相同的。至于分割线上下打印出的地址不一样那是因为源代码中使用Person()构造new了两次,每new一次其实就是在堆上开辟了一块新的空间,所以相当于在堆上开辟了两个不同地址的空间,而person1,person2分别为这两个空间的地址,所以才会不一样。
这里还有一个小知识的
关于this 和 super的区别:
两者最大的区别就是super是子类访问父类的操作,而this是本类的访问。
static关键字
在java中static用于修饰属性和方法。
static声明的属性和方法的生命周期和类相同,在整个应用程序执行期间都有效。
注:
static修饰的属性和方法属于类
普通属性和方法属于对象
Static修饰属性(类中属性)
在一个类中定义普通属性,每new一个对象就会在堆上分配一片空间,空间中是各属性值的存储,但是static修饰的属性不是保存在堆中,而是在全局数据区,在整个生命周期中只有一个存在(与new的对象无关),对所有对象共享。
如图所示:
图中new了两个对象,普通属性拷贝了两份分别存放在不同的堆空间,对象间不能共享同一属性,但是static属性只有一份,在全局数据区,两个对象共享一个属性。
描述共享属性,只需在属性前加static关键字就可以
static属性又称为类属性,保存在全局数据区(所有对象共享区域)的内存之中,所有对象都可以进行该数据区的访问
注:
1.static属性可以通过类名调用,与对象实例化无关
2.所有非static属性必须在对象实例化后使用,而static属性不受对象实例化限制
3.在定义类中属性时一般不使用static,只有需要共享属性,或者不受对象实例化约束的属性时使用static.
4.局部变量不能用static修饰。
static方法
static方法和static属性特质基本相同,可以通过类名直接调用,与对象实例化无关
注:
1.所有的static方法不允许访问非static定义的属性或方法。因为static与对象实例化无关,而非static定义的属性或方法都与对象实例化有关,两个的创建时间不同,权限不同。static创建在非static创建之前,static存在而非static不一定存在所以不能访问。
2.所有非static方法允许访问static方法或属性。非static创建在static创建之后,所以非static存在则static必然存在,所以可以访问。
final
final可以用来定义类、方法、属性
有以下特点:
- 使用final定义的类不能有子类(String类便是使用final来定义的)
- final一旦修饰一个类之后,这个类的所有方法默认都会加上final(不包括成员变量)
- 使用final定义的方法不能被覆写
- 使用final定义的变量就成为了常量,常量必须在声明时赋值,并且不能够被修改
- final成员变量必须在声明的时候初始化或者在构造器中初始化,否则会报编译错误
- 不能对fianl变量再次赋值
- 没有在声明时初始化final变量得到的称为空白final变量,它们必须在构造器中初始化,或者调用this()初始化
对于一个final变量,如果是基本数据类型的变量,则其数据一旦在初始化后就不能改变;如果是引用类型的变量,则在对其初始化后就不能再指向另一个对象
这里还有一个关于final常见的问题,就是为什么局部内部类和匿名内部类只能访问局部final变量?
简单来说就是因为Java是值传递的;为了解决方法结束后变量的生命周期跟着结束,那么此时内部类中继续访问方法中的局部变量就不可能了这一问题,Java采用了复制的手段来解决,意思就是说如果局部内部类或者匿名内部类中使用了局部变量那么在编译期间编译器会默认在匿名内部类或者局部内部类的常量池中添加一个内容相等的字面量也就是匿名内部类或局部内部类使用的变量是另一个局部变量,只不过值和方法中的局部变量相等,就相当于产生了一个局部变量的拷贝。学过c语言的我们都知道在传参时如果传入的是一个临时拷贝那么改变拷贝变量的值并不会改变原变量的值,这样就会产生数据的不一致,所以就规定必须将变量限制为final类型,这样就解决了数据的不一致性。
所以fianl修饰局部变量的目的就是为了防止修改这个参数的值,同时也是一种声明和约定,强调这个参数是不可变的
对于fianl继续深究其实还有很多内容但是由于本人理解有限就写出了一些自己的想法。
想深入了解的可以参考下面的文章
https://blog.csdn.net/niguang09/article/details/6035813
http://www.cnblogs.com/dolphin0520/p/3736238.html