一. this 关键字
this指向自己的引用, 即当前方法所在的对象. 它的一个主要的作用是将自己这个对象当作参数, 传送给别的对象中的方法.
用法一: 当成员变量与局部变量重名时, 用this来做区分
/*** * 当成员变量与局部变量重名时, 用this区分 * this表示当前对象的变量 * @author hlwyf_000 * */ public class TestThis { int age; public void changeAge(int age){ this.age = age; } public static void main(String[] args){ TestThis testThis = new TestThis(); testThis.age = 30; testThis.changeAge(45); System.out.println(testThis.age); } }
运行结果: 45
在下一代码中, 如果不用this.age而用age, 那么, 将无法区分怎么赋值, 出现自己赋值给自己的情况.
而使用了this.age, this表示当前对象的, 所以this.age就是当前对象的age, 从而区分开来.
public void changeAge(int age){ this.age = age; }
用法二: 将自身作为一个对象传递给其他方法
看上去比较乱, 仔细理解里面的运作过程.
设计模式: 使用者模式
1 /*** 2 * 把自身对象作为一个参数传递给其他方法 3 * @author hlwyf_000 4 * 5 */ 6 public class ThstThis2 { 7 public static void main(String[] args){ 8 A a = new A(); 9 } 10 } 11 12 class A{ 13 public A(){ 14 B b = new B(this); //这里的this表示A对象,将整个A给传进去了!在B中就可以使用A的方法 15 b.print(); 16 } 17 public void printA(){ 18 System.out.println("print of A!"); 19 } 20 } 21 22 class B{ 23 A a; 24 public B(A a){ 25 this.a = a; //这里的this表示B对象 26 } 27 public void print(){ 28 System.out.println("A"); 29 this.a.printA(); //这里也可以使用 a.printA(); 30 } 31 32 }
运行结果:
A
print of A!
问题分析: 在class B 中去掉 A a; 将会如何? 代码如下:
将class B修改为:
1 class B{ 2 public B(A a){ 3 a.printA(); 4 } 5 public void print(){ 6 System.out.println("A"); 7 //a.printA(); 8 } 9 10 }
运行结果:
print of A!
A
正常!
去掉注释:
class B{ public B(A a){ a.printA(); } public void print(){ System.out.println("A"); a.printA(); } }
结果报错! 为什么会这样呢?
分析: public B(A a) 中的a是形参, 形参分配在局部变量那里, 放在内存的栈区, 当构造函数这个方法执行完毕之后, 它的生命周期就消失掉了, 那么内存就释放了.因此在下面如果再使用形参a, 由于在内存已经不存在了, 所以无法调用, 编译器报错! 而解决这一问题的方法就是如上面运行正确的代码所示, 即在类里面定义一个成员变量, 再把形参的值赋值给这个成员变量 (注意: 类里面的成员变量类型可以是 类, 数组, 接口, 在上一份笔记中有提及), 而成员变量的消失, 要等垃圾回收器, 这种情况下是内存已满的时候, 一般很少发生.
正确代码如下:
class B{ A a; //定义成员变量 public B(A a){ a.printA(); } public void print(){ System.out.println("A"); this.a.printA(); } }
二.类变量与实例变量的区别
注意: static属于类的, 不是属于对象的! 不是成员属性, 在内存中属于静态区!
/**易错知识点:
public class Person { int age; static String classer; } public class Mathod { }
在同一个文件中, 不能定义两个public类, 只能定义一个public类, 在Mathod类中, 去掉public就正确.
****/
代码举例分析:
1 public class Person { 2 int age; //成员变量, 在内存中放在堆区里 3 static String classer; //类变量, 在内存中放在静态区里 4 } 5 6 class Mathod { 7 public static void main(String args){ 8 //定义两个Person类对象 9 Person person1 = new Person(); 10 Person person2 = new Person(); 11 12 person1.age = 1; 13 person2.age = 2; 14 15 person1.classer = "ABC!"; 16 System.out.println(person1.classer); 17 System.out.println(person2.classer); 18 } 19 20 }
初步编译, 无法编译通过, 寻找原因, 发现:
1. 文件名必须与public类名相同.
2. 编译器从public类的main函数入口进入, 如果没有main函数, 则不予编译. 那么, 上述代码中犯了这些错误.
修改如下:
1 class Person { 2 int age; //成员变量, 在内存中放在堆区里 3 static String classer; //类变量, 在内存中放在静态区里 4 } 5 6 public class Mathod { 7 public static void main(String[] args){ 8 //定义两个Person类对象 9 Person person1 = new Person(); 10 Person person2 = new Person(); 11 12 person1.age = 1; 13 person2.age = 2; 14 15 person1.classer = "ABC!"; 16 System.out.println(person1.classer); 17 System.out.println(person2.classer); 18 } 19 20 }
编译结果:
ABC!
ABC!
从这里看出, 在16行和17行中, 输出的内容一样. 因为, classer放在内存的静态区里, 对于在栈区的局部变量person1和person2都可以调用!
对于这个代码的内存分配图如下:
这就是类变量和实例变量的区别!
对象是通过类来创建的, 因此创建对象时需要加载相应的类. 一个类可以创建多个对象, 每个对象都有属于自己的实体.
区别:
1.类变量(如上面的classer)在类加载时分配内存, 实例变量(如上面的age)是在创建对象时分配内存, 类变量在程序退出时释放内存, 对象不存在, 实例变量就不存在.
2.类变量被所有对象共享, 即同一类的对象共享此类的类变量, 实例变量为每个变量独有, 操作自己的实例变量不会影响其他对象.
3.类变量一般通过类名来调用.
三. 类方法和实例方法的区别
类加载时,类方法被分配入口地址, 实例方法是在第一个对象创建时被分配入口地址.
类方法一般通过类名来调用.
类方法, 就是加上static
在类方法中不能使用 this 关键字, 因为this代表当前对象, 类方法是在类加载时就存在, 而此时对象还不存在
类方法和类变量被所有的对象共享
class Person { int age; //成员变量, 在内存中放在堆区里 static String classer; //类变量, 在内存中放在静态区里 static void classmathod(){ System.out.println("这是一个类方法"); } void mathod(){ System.out.println("这是一个实例方法"); } } public class Mathod { public static void main(String[] args){ //定义两个Person类对象 Person person1 = new Person(); Person person2 = new Person(); System.out.println("Person1分别调用类方法和实例方法"); person1.mathod(); person1.classmathod(); System.out.println("Person2分别调用类方法和实例方法"); person2.mathod(); person2.classmathod(); System.out.println("Person类分别调用类方法"); Person.classmathod(); //注意不能调用实例方法!!! } }
运行结果:
Person1分别调用类方法和实例方法
这是一个实例方法
这是一个类方法
Person2分别调用类方法和实例方法
这是一个实例方法
这是一个类方法
Person类分别调用类方法
这是一个类方法