Java基础篇--Java类的结构与关键字(2018.8.24)

public class DemoClass {//类的声明
private String id;//类的属性,实例变量,每个对象均有其自己的实例变量
private final String sex=”男”;//类的属性,实例变量,每个对象均有其自己的实例变量
private static final String NAME=”测试”;//类的属性,静态变量,为所有类的实例对象共享。
public DemoClass() {//类的构造器,里面的内容说明了如何通过这个类构造对象
this.id=”11111”;
}
public DemoClass(String id) {//类构造器的重载,可以自己传入参数构造类的实例对象。
this.id=id;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getSex() {
return sex;
}

}
以上是一个简单的类的结构的示例。以此作为前面几篇博客的补充说明。接下来探讨下Java的两个重要的关键字,static和final。

static关键字

static关键字是Java当中比较重要的关键字。用来修饰静态的元素,什么叫静态的元素呢?静态的元素就是指那些不需要实例化对象只需要直接通过类去访问的元素。static关键字在Java中可以修饰:成员变量、成员方法、代码块及内部类。

1. static变量
static变量也称作静态变量,静态变量和非静态变量(实例变量)的区别是:静态变量被所有的对象所共享,在内存中只有一个副本,它当且仅当在类初次加载时会被初始化。而实例变量是对象所拥有的,在创建对象的时候被初始化,存在多个副本,各个对象拥有的副本互不影响。static成员变量的初始化顺序按照定义的顺序进行初始化。对静态变量的引用有两种方式,分别为“类.静态变量”和“对象.静态变量”。实例变量属于对象,只有对象被创建后,实例变量才会被分配空间,才能被使用,他在内存中存在多个副本,只能用“对象.实例变量”的方式来引用。

2.static方法

static方法一般称作静态方法,由于静态方法不依赖于任何对象就可以进行访问,因此对于静态方法来说,是没有this和super的,因为它不依附于任何对象,既然都没有对象,就谈不上this和super了。并且由于这个特性,在静态方法中不能访问类的实例成员变量和实例成员方法,因为实例成员方法/变量都是必须依赖具体的对象才能够被调用。静态方法中只能访问该类或其他类的静态变量,不能访问该类或其他类的实例变量。反过来则可以,因为静态的变量在类初次加载时就已经在内存中分配空间了,而不是创建对象的时候分配空间。

3.static代码块

static代码块在类中是独立于成员变量和成员函数的代码块,他不在任何一个方法体内,JVM在加载里的时候会执行static代码块,如果有多个static代码块,JVM将会按顺序来执行,static代码块经常会被用来初始化静态变量,需要注意的是static代码块只会被执行一次。可以用static代码块来优化程序性能,即将每个对象都需要初始化的相同的变量放在static代码块中。

4.static内部类

static内部类是指被申明为static的内部类,它可以不依赖于外部类实例对象而被实例化,而通常的内部类需要外部类实例化后才能实例化。静态内部类不能与外部类有相同的名字,不能访问外部类的普通成员变量,只能访问外部类中的静态成员和静态成员方法,只有内部类才能被申明为static。

final关键字

final是Java中一个保留的关键字,Java保留的关键字意味着将不能将这些关键字当做变量名称。final 可以声明成员变量、方法、类以及局部变量(即上面类中方法中的变量),一旦将某一个类的元素声明成final,该元素就不能再改变了,即final修饰的元素初始化完毕后是只读的,如果程序中有对该元素进行再次改变,编译器会报编译错误。

1. final变量

使用final修饰的成员变量、静态变量、局部变量都可以叫做final变量。final变量经常和static关键字一起使用,作为常量,final变量是只读的。final变量是final使用最广的地方,更是final的重点,对于一个final变量,如果其类型是基本数据类型的变量,则其数值一旦被初始化之后就不可修改;如果是引用类型的变量,则在对其进行初始化之后便不能让其指向另一个对象。

2. final方法

使用final修饰方法的主要原因是把方法锁定,防止任何继承类修改它的含义。因此,只有在想明确禁止该方法在子类中被覆盖的情况下才将方法设置为final的。 类的private方法会隐式的被指定为final方法。final方法比非final方法要快,因为在编译的时候已经静态绑定了,不需要在运行时再动态绑定。

3. final类

使用final修饰的类叫做final类。final类的功能通常是完整的,他们不能被继承。一旦一个类被声明为final,其内部的成员方法也都会被隐式地指定为final。Java中有许多类是final的,例如String、Integer及其他基本类型的包装类。

使用final关键字的好处

1.final关键字提高了系统的性能,JVM和Java应用都会缓存final变量。
2.final变量可以安全地在多线程环境下进行共享而不需要额外的同步开销。
3.使用final关键字,JVM会对方法、变量、类进行优化。
4.使用final关键字可以用来构造不可变类。

final关键字的深入探讨

1.final成员变量必须在声明的时候初始化或者在构造器中初始化,否则就会编译错误。
2.final变量无法再次赋值,因为其只初始化一次。
3.匿名类中所有变量必须是final变量。
4.final方法不能被重写,final类不能被继承。
5.接口中声明的所有变量本身是final的。
6.final和abstract这两个关键字是相反的,final类就不可能是abstract(抽象)的。因为abstract类可以进行继承进行实现,而final类不行。
7.final方法在编译阶段绑定,称为静态绑定(static binding)。
8.Java中final变量就是常量,通常变量名要大写。
9.final变量和普通变量的区别。

10.public class Test{
public static void main(String[] args){
String a = “hello2”;
final String b = “hello”;
String d = “hello”;
String c = b + 2;
String e = d + 2;
System.out.println((a == c));
System.out.println((a == e));
}
}
输出结果为:true,false。
String是一个final类,final类的特点就是共享数据,==是地址的比较,而final类的String相同的字符串指向的是同一个地址。String类中用””中的字面值创建对象时,都会先在串池空间中查找,如果有就返回字符串地址,没有则串池里创建一个对象。如果是new在堆空间创建String类对象,则不会有这个过程(String做字符串连接也是一样,每连接一次相当于创建一个对象)。输出的值一个是true,一个是false。这里面就是final变量和普通变量的区别了,当final变量是基本数据类型以及String类型时,如果在编译期间能知道它的确切值,则编译器会把它当做编译期常量使用。也就是说在用到该final变量的地方,相当于直接访问的这个常量,不需要在运行时确定。由于变量b被final修饰,因此,会被当做编译器常量,所以在使用到b的地方会直接将变量b替换为它的值。而对于变量d的访问却需要在运行时通过链接来进行。所以在程序运行时,变量c就已经是”hello2”且指向的是和变量a一样的地址,而变量d指向的内存空间却不是和a一样的地址。

11.被final修饰的引用变量指向的对象内容是可改变的,引用变量被final修饰之后,虽然不能再指向其他对象,但是它指向的对象内容是可变的。

12.final和static的区别:static使得被修饰的内容在内存中只有一份,JVM只会为静态变量分配一次内存,在加载过程中完成静态变量的内存分配,可用类名直接访问。而final只是保证变量不可改变,不可改变的是引用的指向,具体的引用指向的值是可以改变的。

13.为什么局部内部类和匿名内部类只能访问局部final变量?
所谓“局部内部类”就是在对象的方法成员内部定义的类。而方法中的类,访问同一个方法中的局部变量,是天经地义的。那么为什么要加上一个final呢?原因是:内部类对象的生命周期可能会超过局部变量的生命周期。当方法被调用时,局部变量在栈中被创建,当方法执行结束时,退栈,这些局部变量全部都被清除,但是局部内部类和匿名内部类,他们的生命周期是和其他类一样的。当创建一个该局部类对象后,只有没有其它人再引用它时,它才能死亡。完全可能一个方法已调用结束(局部变量已死亡),但该局部类的对象仍然活着。即局部类的对象生命期会超过局部变量。所以解决方法是:局部内部类的对象可以访问同一个方法中的局部变量,只要这个变量被定义为final。那么,为什么定义为final变可以呢?定义为final后,编译程序就好实现了,具体实现方法是:将所有的局部内部类对象要访问的final型局部变量,都成为该内部类对象中的一个数据成员。这样,即使栈中局部变量(含final)已死亡,但由于它是final,其值永不变,java会在内部类当中创建一个final型局部变量的拷贝,因而局部内部类对象在变量死亡后,照样可以访问final型局部变量。

猜你喜欢

转载自blog.csdn.net/qq_31507627/article/details/82112130