Static与this关键字
1static
static是什么意思?静止的;
他是一个属性。
属性:
静态属性:在类体中,方法外被static关键字修饰的。
成员属性:在类体中,方法外没有带static关键字。
方法:
构造方法:不用写返回值类型,方法名为类名.
静态方法:被static关键字修饰的方法 。static test();
成员方法:不带static关键字的方法 。 test();
- 静态变量
我们时常会遇到这样一种情况,某个类的对象他们有一些共同的特点。
class TestUser
{
private String name; // 很可能不一样
private int age; // 很可能不一样
private String career; // 假设都是程序员
public TestUser() {
}
public TestUser(String sName,int uAge , String uCareer) {
name = sName;
age = uAge;
career = uCareer;
}
public String toString() {
return "{ " + name + ", " + age +", " + career + " }";
}
}
public class TestUser1
{
public static void main(String[] args) {
TestUser wrr = new TestUser("wrr", 21, "程序员");
TestUser lr = new TestUser("lr", 20, "程序员");
System.out.println(wrr);
System.out.println(lr);
/*输出结果
{ wrr, 21, 程序员 }
{ lr, 20, 程序员 }
*/
}
}
其内存图为:
在这里我们可以看见career职业这个属性对每个对象来说都是相同的,如果有很多的对象,他被大量的在堆内存中创建,这样就造成了内存的浪费,此时我们就想,是否有什么东西能够让他被重复的部分不被重复创建呢?答案就是static。
上面内存图中可以看出jvm内存主要分为三大块。
栈中主要储存局部变量,堆中储存成员变量,所以我们要把他存放在方法区内存中去。
被static修饰的变量,方法都会被存储在方法区内存中。方法区内存最先加载内容且在其被加载完成之后内容就被固定了,static修饰的变量与方法在类被加载的时候被加载,若是变量则会在内加载的时候被赋值,且与类加载一样都只执行一次。
那为什么其可以被共用?因为其修饰的变量是与类一个级别的。是类中所有的对象都共有的,值是一样的。我们用"类名."就可以使用它。我们可以把其理解为这是所有对象都共有的特征,比如人和动物都有个共同的概念,他们都是生命。
class TestUser
{
private String name; // 很可能不一样
private int age; // 很可能不一样
private static String career = "程序员"; // 假设都是程序员
public TestUser() {
}
public TestUser(String sName,int uAge) {
name = sName;
age = uAge;
}
public String toString() {
return "{ " + name + ", " + age +", " + career + " }";
}
}
public class TestUser1
{
public static void main(String[] args) {
TestUser wrr = new TestUser("wrr", 21);
TestUser lr = new TestUser("lr", 20);
System.out.println(wrr);
System.out.println(lr);
/*输出结果
{ wrr, 21, 程序员 }
{ lr, 20, 程序员 }
与之前一样
*/
}
}
所以说当我们遇到这种类中所有对象都共有一个成员属性的时候我们把它设为静态变量,而且因为他是累计别的对象所以我们需要用"类名."来访问他。
注意:静态变量是类级别的,所以他在main函数压栈之前便已经加载好了。
- 静态代码
既然有静态变量,那么也就存在静态的代码
static {
java语句;
java语句;
…………
}
public class TestUser1
{
private int i = 100;
static {
System.out.println("静态代码start");
System.out.println("i = " + i);
System.out.println("静态代码end");
//如果这里输出则说明i与类一起被加载静态代码后于main()
// TestUser1.java:7: 错误: 无法从静态上下文中引用非静态 变量 i
// System.out.println("i = " + i);
// ^
//由此可知其先于main
}
public static void main(String[] args){
System.out.println("main start");
System.out.println("main end");
}
}
public class TestUser1
{
private static int i = 100;
static {
System.out.println("静态代码start");
System.out.println("i = " + i);
System.out.println("静态代码end");
/*输出结果
静态代码start
i = 100
静态代码end
main start
main end
这样更加可以看出其顺序。
*/
}
public static void main(String[] args){
System.out.println("main start");
System.out.println("main end");
}
}
顺序:静态代码块(以及类等)——main——调用
如果我们在静态代码块中构造一个对象那么其还是在堆内存中申请对象,只不过说其引用地址存放在方法区内存中。
那么不加static的代码块是什么?可以被执行吗?
实例代码块
{
java语句;
java语句;
…………
}
那么他的执行顺序又是如何呢?
public class TestUser1
{
public TestUser1(){
System.out.println("构造方法start");
}
private int i = 100;
{
System.out.println("实例代码start");
System.out.println("i = " + i);
System.out.println("实例代码end");
/*输出结果
实例代码start
i = 100
实例代码end
构造方法start
实例代码start
i = 100
实例代码end
构造方法start
这样更加可以看出其与构造方法有关,每次构造都会执行一次,且在构造方法之前。
*/
}
public static void main(String[] args){
TestUser1 t1 = new TestUser1();
TestUser1 t2 = new TestUser1();
}
}
当我们把career设为静态变量后内存图如下:
2.this关键字
this(这个)他被用来表示一个确定的对象。
通常用 this.变量
-应用实例
重名:在我们进行赋值的时候会出现这样一个问题,当成员变量和形参同名的时候,他的赋值会出现问题,那么是什么问题?
class TestUser
{
private String name;
private int age;
private static String career = "程序员";
public TestUser() {
}
public TestUser(String name,int age) {
name = name;
age = age;
//因为就近原则这里的name和age都是指构造方法中的形参本身。
//左为形参,右边为实参的值相当于自己给自己赋值,对于成员变量没有影响。
}
public String toString() {
return "{ " + name + ", " + age +", " + career + " }";
}
}
public class TestUser1
{
public static void main(String[] args) {
TestUser wrr = new TestUser("wrr", 21);
TestUser lr = new TestUser("lr", 20);
System.out.println(wrr);
System.out.println(lr);
/*输出结果
{ null, 0, 程序员 }
{ null, 0, 程序员 }
为什么没有被赋值?因为在java中存在就近原则,这里的两个age都是指的同一个age即构造方法中的形参自然不存在赋值。
*/
}
}
class TestUser
{
private String name;
private int age;
private static String career = "程序员";
public TestUser() {
}
public TestUser(String name,int age) {
this.name = name;
this.age = age;
}
public String toString() {
return "{ " + name + ", " + age +", " + career + " }";
}
}
public class TestUser1
{
public static void main(String[] args) {
TestUser wrr = new TestUser("wrr", 21);
TestUser lr = new TestUser("lr", 20);
System.out.println(wrr);
System.out.println(lr);
/*输出结果
{ wrr, 21, 程序员 }
{ lr, 20, 程序员 }
我们通过使用this关键字来解决这个问题,this标注后他表示左边的name与age是成员变量与右边的形参区分开来,这样就实现了对变量的赋值。
*/
}
}
//通过上面的例子我们可以对其功能有一定的了解,他指定了谁是成员变量。
this是什么?
我们可以看到,this的使用方法是 this.变量
而’.‘的使用为 ” 引用 . 成员属性 “由此可见this为一个引用他存的是一个地址即其所对应对象的堆内存首地址,这样就不难理解了,’ . '是通过地址来调用对象中的成员变量以此来区分成员变量与局部变量。
内存图如下:
同时,在很多的代码中都存在this关键字来指定输出的对象,例如println(xx),他是如何找到xx的就是省略了参数中的this,这个在查看源码的时候可以发现。