*this关键字
问题的引出:
package testobject;
class Person {
private String name;
Person(String name) {
name = name; // 问题的引出,name是局部变量,都在栈内存中,不会去访问堆内存中的name,
// 因此不会对对象中的name进行赋值操作。
}
void speack() {
System.out.println("name:" + name);
}
}
public class TestObject {
public static void main(String[] args) {
Person p = new Person("Jack");
p.speack();
}
}
内存解析:
*this的使用场景及细节
回顾:构造函数可以访问一般函数,而一般函数是不能访问构造函数的(除非新建对象的时候),那构造函数怎么可以访问构造函数呢?
注:一个类中所有的成员要想使用都得用对象来调用(除了静态变量)。一般都是省略了this.
分析:
package testobject;
class Person {
private String name;
private int age;
Person(String name) {
this.name = name;
}
Person(String name, int age) {
this.name = name;
// 分析:这一句与上面Person(Stringname)这个构造函数的功能一样,因此为了提高函数的重用性,
// 我们可以来在这个构造函数调用上面Person(String name)这个构造函数.
// 但是应该怎么调用?
// Person(name); 如果直接写这句,是不能实现这样的功能的,因为这句的含义其实是 this.Person(name);
// 而Person(name)本身就是为了初始化对象来用的,前面如果再加上this,就有些说不通了[this是指对象,但都还没有用Person来初始化它,
// 又怎么能调用Person(name)呢?]
// 因此正确的调用构造函数的方法应该为:
// this(name);
this.age = age;
}
void speack() {
System.out.println(name + "..." + age);
}
}
public class TestObject {
public static void main(String[] args) {
Person p = new Person("Jack", 10);
p.speack();
}
}
我们来画个上例的内存示意图:
1.
2.
所以this还有这样的功能:在构造函数调用其他构造函数,只能定义在构造函数的第一行。【因为初始化函数必须先执行】
细节:
Person(String name, int age) {
this.age = age;
this(name);//编译出错:Constructor call must be the first statement in a constructor
}
*this关键字的基本应用
this代表本类对象
package testobject;
class Person {
private String name;
private int age;
Person(String name) {
this.name = name;
}
Person(String name, int age) {
this(name);
this.age = age;
}
void speack() {
System.out.println(name + "..." + age);
}
/* 判断是否同龄人 */
public boolean compare(Person p) {
if(this.age == p.age)//这句也可以写成if(age == p.age) 因为在栈内存中,没有与age同名的局部变量,
//但是为了提高阅读性,建议写成this.age == p.age
return true;
else
return false;
/*
判断语句简洁些:
1.三目运算符
return (this.age == p.age)?true:false;
2.更为简洁的
return this.age == p.age;
*/
}
}
public class TestObject {
public static void main(String[] args) {
Person p1 = new Person("Jack", 10);
Person p2 = new Person("Lisa", 12);
boolean b = p1.compare(p2);
System.out.println(b);
}
}
====================================================================================================================================
*另一个关键字:static——数据共享
static本身即是关键字也是修饰符,那它到底什么时候用,怎么用呢?
问题引入:
我们创建对象,对象是来封装数据的,但是当数据中有所有对象共同的同样值的数据时,这个时候再创建对象的时候,就会很占内存的。
成员被static修饰之后,有什么好处?
因为static修饰之后,数据就变成了共享数据,所以该数据要在对象生成前要先有。
被static修饰的数据,不仅可以被对象调用使用,而且也可以直接被类名来调用使用。
被static修饰的变量叫做静态变量,它的好处有:1.有两种调用方式了 2.可以不用创建对象,就能使用了。
静态变量就不要称作成员变量。
实例变量:实例就是对象。
private String name;
private int age; //实例变量<------->成员变量
static private String country = "CN";//静态变量<------>类变量[注:和类类型变量不一样]
虚拟机在加载类的时候,如果加载太多了,会有垃圾回收机制,释放很长时间不在用的类。
静态变量不存在于堆内存中,因为堆内存中不可能单独存放一个数据,它只能存实体。
那静态变量会不会存在栈中呢?不会。栈内存一般生命周期比较短,而且栈里面的数据是随着方法的加载而出现的。
那静态变量在哪呢?
内存分类:
1.本地方法区---->for 系统方法
2.寄存器---->for CPU
3.方法区
4.堆
5.栈
方法就放在方法区。
静态变量存在方法区的静态区中,所以也叫对象的共享数据。
总结:
*静态使用的一些细节:
静态方法:public static void speak(){}
error:无法总静态上下文中引用非静态变量 为什么?
因为静态方法是先存在的,先于对象的创建,成员变量是在对象创建的时候,存在的。
静态方法可以用类名来访问。
在访问非静态变量时,省略了this,在访问静态变量时,省略了类名。
*main函数解析
*静态成员的内存解析
1.程序被加载到内存是,当在dos界面执行java语句开始的
*什么时候使用静态呢?
*静态代码块
静态代码块:随着类的加载,而执行。而且只执行一次。
作用:给类初始化。
不是所有类都是用构造函数初始化的。
*构造代码块
构造函数不止是定义数据
定义在类中的代码块:称作构造代码块,和对象有关,创建几个对象,运行几次。是给所有对象初始化用的。
而构造函数是给对象有针对性的初始化。
定义在函数里面的代码块叫做局部代码块。
package testobject;
class Person {
private String name;
{
cry();
}
Person() {
name = "baby";
// cry();
}
Person(String name) {
this.name = name;
// cry();
}
public void cry() {
System.out.println("wawa...");
}
public void speak() {
System.out.println("name:" + name);
}
}
public class TestObject {
public static void main(String[] args) {
Person p1 = new Person();
p1.speak();
Person p2 = new Person("Jack");
p2.speak();
}
}
*数组工具类中static的使用
练习:
求数组的最大值=========[del *.class],Java编辑器会检查当前类是否用到其他类,如果检查到有的话,java编译器会自动给出编译。
1.
public class ArrayMain {
public static void main(String[] args) {
int[] arr = { 12, 47, 98, 3, 7, 78 };
int maxIndex = 0;
for (int i = 1; i < arr.length; i++) {
if (arr[i] > arr[maxIndex])
maxIndex = i;
}
System.out.println("Max:" + arr[maxIndex]);
}
}
2. 方法1,是面向过程的,而且如果要对多个数组进行求最大值,那么就要写很多重复代码,不推荐,接下来做下完善。
public class ArrayMain {
public static void main(String[] args) {
int[] arr = { 12, 147, 98, 3, 7, 78 };
int max = getMax(arr);
System.out.println("Max:" + max);
}
public static int getMax(int[] arr) {
int maxIndex = 0;
for (int i = 1; i < arr.length; i++) {
if (arr[i] > arr[maxIndex])
maxIndex = i;
}
return arr[maxIndex];
}
}
3.但是上面的如果是其他类也想用的话,就不是很好了,所以我们推荐将这些都封装在一个工具类中,做如下修改:
ArrayMain.java文件代码:
public class ArrayMain {
public static void main(String[] args) {
int[] arr = { 12, 147, 98, 3, 347, 78 };
ArrayTools tool = new ArrayTools();
int max = tool.getMax(arr);
System.out.println("Max:" + max);
tool.selectSort(arr);
tool.print(arr);
int index = tool.getIndex(arr, 31);
System.out.println("index:" + index);
}
}
ArrayTools工具类:
package array;
public class ArrayTools {
public int getMax(int[] arr) {
int maxIndex = 0;
for (int i = 1; i < arr.length; i++) {
if (arr[i] > arr[maxIndex])
maxIndex = i;
}
return arr[maxIndex];
}
public int getIndex(int[] arr, int key) {
for (int i = 0; i < arr.length; i++) {
if (arr[i] == key)
return i;
}
return -1;
}
public void selectSort(int[] arr) {
for (int i = 0; i < arr.length - 1; i++) {
for (int j = i + 1; j < arr.length; j++)
if (arr[i] > arr[j])
swap(arr, i, j);
}
}
private void swap(int[] arr, int i, int j) {
int temp = arr[i];
arr[j] = arr[j];
arr[j] = temp;
}
public void print(int[] arr) {
for (int n : arr)
System.out.print(n + ",");
System.out.println();
}
}
4.尽管上面很好,但还是存在问题
观察ArrayTool里面的代码可以看出里面没有任何的成员变量,也就是说这个工具类中的方法都没有访问到任何成员变量数据,因此我们就可以对方法添加静态修饰词static。
这样的话,在main函数中,就可以不用生成对象,再用对象来调用方法了,这样就会节省内存空间。
修改代码如下:
main函数中:
package array;
public class ArrayMain {
public static void main(String[] args) {
int[] arr = { 12, 147, 98, 3, 347, 78 };
// ArrayTools tool = new ArrayTools();
int max = ArrayTools.getMax(arr);
System.out.println("Max:" + max);
ArrayTools.selectSort(arr);
ArrayTools.print(arr);
int index = ArrayTools.getIndex(arr, 31);
System.out.println("index:" + index);
}
}
工具类函数中:
package array;
public class ArrayTools {
public static int getMax(int[] arr) {
int maxIndex = 0;
for (int i = 1; i < arr.length; i++) {
if (arr[i] > arr[maxIndex])
maxIndex = i;
}
return arr[maxIndex];
}
public static int getIndex(int[] arr, int key) {
for (int i = 0; i < arr.length; i++) {
if (arr[i] == key)
return i;
}
return -1;
}
public static void selectSort(int[] arr) {
for (int i = 0; i < arr.length - 1; i++) {
for (int j = i + 1; j < arr.length; j++)
if (arr[i] > arr[j])
swap(arr, i, j);
}
}
private static void swap(int[] arr, int i, int j) {
int temp = arr[i];
arr[j] = arr[j];
arr[j] = temp;
}
public static void print(int[] arr) {
for (int n : arr)
System.out.print(n + ",");
System.out.println();
}
}
5.这样操作固然可以节省空间,但是当我们把这个工具类,交给别人使用的时候,怎么防止他人会使用ArrayTools tool = new ArrayTools();这个方法创建个对象,之后在用对象进行操作呢,这样一样还是会浪费空间的,还是没有达到我们的目的。怎样操作可以防止呢?也就是说如何强制限制用户不让他创建这个对象。
方法很简答,直接在工具类的方法中复写构造函数并设置为私有。
public class ArrayTools {
private ArrayTools() {
}//构造函数私有化
}
*数组工具类——注释文档
文档注释javadoc
怎么使用呢?