目录
可修饰部分
static:成员变量、方法、代码块(静态代码块)、内部类(静态内部类)
final: 类、成员变量、方法、局部变量
一、static
当设计某个class时,其实就是在描述其外观长相以及行为举措。除非以new 来产生对象,否则并不存在任何实质对象。产生对象之际,存储空间才会分配出来,其函数才可供外界使用。
但是有两种情况上述方式无法解决。
第一种:你希望不论产生了多少对象或是不存在任何对象的情形下,那些特定的数据的存储空间都只有一份。
第二种:你希望某个函数不要和class object绑在一起,通过static 关键字可以处理这两种情况。
简言之,static的主要作用是:方便在没有创建对象的情况下来进行调用(方法/变量)。
按照是否静态的对类成员变量进行分类可分两种:
一种是被static修饰的变量,叫静态变量或类变量;
另一种是没有被static修饰的变量,叫实例变量。
两者的区别是:
对于静态变量在内存中只有一个拷贝(节省内存),JVM只为静态分配一次内存,在加载类的过程中完成静态变量的内存分配,可用类名直接访问(方便),当然也可以通过对象来访问(但是这是不推荐的)。
对于实例变量,每创建一个实例,就会为实例变量分配一次内存,实例变量可以在内存中有多个拷贝,互不影响(灵活)。
static是静态修饰关键字,可以修饰变量和程序块以及类方法:
当定义一个static的变量的时候jvm会将将其分配在内存堆上,所有程序对它的引用都会指向这一个地址而不会重新分配内存;
当修饰一个程序块的时候(也就是直接将代码写在static{...}中)时候,虚拟机就会优先加载静态块中代码,这主要用于系统初始化;
当修饰一个类方法时候你就可以直接通过类来调用而不需要新建对象。
1、static修饰变量:
无论一个类生成了多少个对象,所有这个对象共用唯一一份静态的成员变量;一个对象对该静态成员变量进行了修改,其他对象的该静态成员变量的值也会随之发生变化。如果一个成员变量是static的,那么我们可以通过类名.成员变量名的方式来使用它(推荐使用这种方式)。
static变量也称作静态变量,静态变量和非静态变量的区别是:
静态变量被所有的对象所共享,在内存中只有一个副本,它当且仅当在类初次加载时会被初始化。而非静态变量是对象所拥有的,在创建对象的时候被初始化,存在多个副本,各个对象拥有的副本互不影响。static成员变量的初始化顺序按照定义的顺序进行初始化。
2、static修饰方法:
static修饰的方法叫做静态方法。对于静态方法来说,可以使用类名.方法名的方式来访问。
static方法可以直接通过类名调用,任何的实例也都可以调用,因此static方法中不能用this和super关键字,不能直接访问所属类的实例变量和实例方法(就是不带static的成员变量和成员成员方法),只能访问所属类的静态成员变量和成员方法。因为static方法独立于任何实例,因此static方法必须被实现,而不能是抽象的abstract。
static方法只能访问static的变量和方法,因为非static的变量和方法是需要创建一个对象才能访问的,而static的变量/方法不需要创建任何对象。
********
static的数据或方法,属于整个类的而不是属于某个对象的,是不会和类的任何对象实例联系到一起。所以子类和父类之间可以存在同名的static方法名,这里不涉及重载。所以不能把任何方法体内的变量声明为static,例如:
fun() {
static int i=0; //非法。
}
其实理解static是只有一个存储地方,而使用时直接使用,不需要创建对象,就能明白以上的注意事项。
另外,一般的类是没有static的,只有内部类可以加上static来表示嵌套类。
public class StaticTest {
public static void main(String[] args) {
MyStatic.output();
}
}
class MyStatic{
public static void output(){
System.out.println("output");
}
}
内部类
内部类的定义
将一个类定义在另一个给类里面或者方法里面,这样的类就被称为内部类。
内部类可以分为四种:成员内部类、局部内部类、匿名内部类、静态内部类,下面我们逐一介绍这四种内部类。
成员内部类
他定义在另一个类中。一般定义格式如下
class C{
class D{
}
}
因为类C相对与类D在外面,我们且称类C为外部类。
成员内部类可以无条件访问外部类的属性和方法,但是外部类想要访问内部类属性或方法时,必须要创建一个内部类对象,然后通过该对象访问内部类的属性或方法
成员内部类无条件访问外部类的属性和方法
class C{
private String name = "外部类";
public void run(){
System.out.println("外部类奔跑");
}
class D{
public void say(){
System.out.println(name);
run();
}
}
}
外部类访问内部类属性和方法
class C{
private String name = "外部类";
public void run(){
System.out.println("外部类奔跑");
}
/*使用内部类的属性和方法*/
public void eat(){
D d = new D();
System.out.println(d.value);
d.say();
}
class D{
private String value = "DDD";
public void say(){
System.out.println(name);
run();
}
}
}
外部类属性或方法隐藏
如果成员内部类的属性或者方法与外部类的同名,将导致外部类的这些属性与方法在内部类被隐藏,也可按照该格式调用,外部类.this.属性/方法。
class C{
private String name = "外部类";
public void run(){
System.out.println("外部类奔跑");
}
/*使用内部类的属性和方法*/
public void eat(){
D d = new D();
System.out.println(d.value);
d.say();
}
class D{
private String value = "DDD";
private String name = "内部类";
public void say(){
System.out.println(C.this.name);
System.out.println(name);
run();
}
}
}
创建内部类对象
目录
显然成员内部类是寄生于外部类,创建内部类对象就必须先创造外部类对象。之后创建内部类有两种方式。
public class Test10 {
public static void main(String[] args) {
/*方式1创建成员内部类对象*/
C c = new C();
C.D d = c.new D();
/*方式2创建成员内部类对象*/
C.D d1 = c.getClassD();
}
}
class C{
private String name = "外部类";
public void run(){
System.out.println("外部类奔跑");
}
/*创建一个返回D对象的方法*/
public D getClassD(){
return new D();
}
/*使用内部类的属性和方法*/
public void eat(){
D d = new D();
System.out.println(d.value);
d.say();
}
class D{
private String value = "DDD";
private String name = "内部类";
public void say(){
System.out.println(C.this.name);
System.out.println(name);
run();
}
}
}
成员内部类的访问权限
成员内部类前可加上