static,final,static-final

xiaoxiao2021-02-28  97

三个修饰符的作用:提高程序运行性能,优化程序结构

static

static表示"静态" ,“共享”, “全局”, “属于类的” 只能修饰方法和变量和内部类(相当于外部类)

1.修饰成员变量

1.1 引用成员变量的方式建议使用className.var。

1.2 表示类的所有实例共享此变量且可以修改,并且继承A的子类的实例也可以修改变量

用法:

class A{ //非静态成员变量每new出一个实例就在实例的堆区域拷贝一份,互不影响 String name; //静态成员变量属于类,在编译时就将此变量 static int age; //类的方法存在静态存储区(包含类的定义等信息),每个实例在堆里有一个方法的指向,当age使用static修饰时,jvm会将静态变量存放至静态存储区 void M1(){}; void M2(){}; static void main(args){ A a= new A(); }

例子:

public class staticA { static int a=0; int b=1; void M1(){ System.out.println("a:"+a); } public static void main(String args[]){ staticA a= new staticA(); a.M1(); a.a=2; a.M1(); } } 测试:

public class teststaticA extends staticA{ public static void main(String args[]){ teststaticA a=new teststaticA(); a.M1(); a.a=10; a.M1(); teststaticA.a=11; a.M1(); } } 结果:

a:0 a:10 a:11

从内存优化角度看,上面的方法虽然优化了内存,但有个问题,就是每个对象对静态成员变量修改会影响其他对象,可以将成员变量设置成private,在类的构造函数对变量操作,例如

class A{ //类外部无法访问此变量 private static int i; A(){ //每实例化一个对象值自增,A所有实例对象共享此变量 i++; } }

2.修饰成员方法

类的方法本来即是存放在类定义中的(内存静态存储区域),static修饰成员方法可以使用classname.method(),避免了new对象的资源消耗。

2.1 static方法独立于任何实例,因此static方法必须被实现,而不能是抽象的abstract。

2.2 静态方法可以直接通过类名调用,任何的实例也都可以调用,因此静态方法中不能用this和super关键字

2.3 静态的方法可以被继承,但是不能重写。如果父类中有一个静态的方法,子类也有一个与其方法名,参数类型,参数个数都一样的方法,并且也有static关键字修饰,那么该子类的方法会把原来继承过来的父类的方法隐藏,而不是重写。

父类

public class father { int i; public static void m2() { System.out.println("m2"); } } 子类

public class child extends father { public static void main(String args[]) { child child = new child(); child.m1(); } public static void m2(){ System.out.println("子类的静态同名方法隐藏了父类m1"); } }

3.修饰代码块

静态代码块是独立于类成员的语句块,不在任何的方法体内,JVM加载类时会执行这些静态的代码块,如果static代码块有多个,JVM将按照它们在类中出现的先后顺序依次执行它们,每个代码块只会被执行一次,初始化时首先初始化静态块然后普通类成员初始化然后是静态方法(classname.mthod方式调用静态方法则会在实例初始化完成之前执行),最后是实例

例子:

class Book { public Book(String msg) { System.out.println(msg); } } public class staticblock { Book book1 = new Book("book1成员变量初始化"); // static {或者这样写 // book2 = new Book("static成员book2成员变量初始化"); // book4 = new Book("static成员book4成员变量初始化"); // } // 静态代码块 static Book book2 = new Book("static成员book2成员变量初始化"); public staticblock(String msg) { System.out.println(msg); } Book book3 = new Book("book3成员变量初始化"); // 静态代码块 static Book book4 = new Book("static成员book4成员变量初始化"); public static void funStatic() { System.out.println("static修饰的funStatic方法"); } public static void main(String[] args) { staticblock.funStatic(); System.out.println("****************"); staticblock p1 = new staticblock("p1初始化"); } }

4.静态导包

package com.a.b; public class c{ public static void m(Object o){ System.out.println(o); } } 采用static导入包后,在不与当前类的方法名冲突的情况下,无需使用“ 类名.方法名”的方法去调用类方法 //import all method import static com.a.b.c.*; public class t { public static void main( String[] args ) { m("Hello World!"); } /**Output * Hello World! }

final

final修饰符表示“终态”“不可修改”的含义,可以修饰类,成员变量,方法(锁定方法)。

1.修饰类

final修饰的类不可以被继承,finalclass表示这个类不会再被改变,也不允许其他类进行操作,不希望有子类,final类没有可扩展性。

final类成员方法都会被默认指定final关键字,成员变量可以自己定义。

2.修饰方法

final把方法锁定,防任何继承类修改它的含义,final方法可以被继承不可被重写/覆盖。

类的private方法会隐式地被指定为final方法。

例子

public class father { int i; public void m1() { System.out.println("m1"); } public final void m3() { System.out.println("m3"); } }

子类

public class child extends father { public static void main(String args[]) { child child = new child(); child.m3(); } public void m1(){ System.out.println("子类覆盖了了父类的普通m1方法"); } public void m3(){ System.out.println("程序报错,无法覆盖父类final方法"); } }

3.修饰变量。(常量的含义)

3.1 对于一个final变量,如果是基本数据类型(int char String等)的变量,则其数值一旦在初始化之后便不能更改(每个实例的变量而言); final作用于类的成员变量时,类成员变量(局部变量只需要保证在使用之前被初始化赋值即可)必须在定义时或者构造器中进行初始化赋值,旦被初始化赋值之后,就不能再被赋值。

例子

class test{ final int i=0; final String="aaa"; void test(){ i=2;//error final Object obj=new Object(); obj=new Object();//error } void m1(){ final int a;//可以在使用的时候赋值 } }

如果没有在初始化时赋值则可以在构造函数赋值

public class father { final int i; public father(int b){ i=b; } public void m1(int a) { System.out.println("m1:"+i); final int aa = a; System.out.println("m1:"+aa); } public static void m2() { System.out.println("m2"); } public static void main(String args[]){ father father=new father(77); father.m1(88); father father1=new father(66); father1.m1(99); } }

3.2 final变量是个常量,编译器会把它当做编译期常量使用使用到变量的地方会直接替换,非final变量则是在运行时通过链接访问。

例子

public class testvar { public static void main(String[] args) { String a = "hello2"; //对象引用变量a放在栈中,字符串放在字符串池,a指向它 String f="hello2";//f和a指向一个地址所以相等 System.out.println(a==f);//true String aa=new String("hello2"); String ff=new String("hello2"); System.out.println(aa==ff);//flase final String b = "hello";//常量 String c = b + 2; //常量,c指向字符串池的hello2 System.out.println((a == c));//true String d = "hello";//d指向hello String e = d + 2;//字符串对象相加会生成新的字符串对象,而不是查找字符串池,所以对象的引用不同 //==对基本类型的变量比较的是值,引用类型的变量存储的并不是 “值”本身,而是于其关联的对象在内存中的地址 System.out.println((a == e));//false } }

3.3 如果是引用类型的变量(maplist),则在对其初始化之后便不能再让其指向另一个对象,但对象内容可变。

public class testvar { final List<String> list=new LinkedList<String>(); public static void main(String[] args) { testvar r=new testvar(); r.list=new LinkedList();//error r.list.add("a"); r.list.add("b"); Iterator<?> i=r.list.iterator(); while(i.hasNext()){ System.out.println(""+i.next()); } }

static-final

static作用于成员变量用来表示只保存一份副本(内存栈中)每个对象共享这个变量,而final的作用是用来保证变量不可变(每个对象的变量值可以在实例化的时候赋值,每个对象的变量值可以不同)

例子

public class testfinal { public static void main(String[] args) { MyClass myClass1 = new MyClass(); System.out.println(myClass1.i); System.out.println(myClass1.j); System.out.println(myClass1.k); myClass1.i++;//error.每个实例可以保存有不同的final变量值,但一旦赋值无法修改 myClass1.j++;//每个对象都可对static的变量修改 myClass1.k++;//error 实例化赋值之后,实例无法对final修饰的成员变量修改 MyClass myClass2 = new MyClass();//成员变量j的值是myclass1实例化后赋的的值 System.out.println(myClass2.i); System.out.println(myClass2.j); System.out.println(myClass2.k); } } class MyClass { public final double i = Math.random(); public static double j = Math.random();//MyClass实例化后得到的j值保存在栈中,被所有实例共享 public static final double k = Math.random(); //public static double j ; public MyClass(){ //j = Math.random();//每个实例化都会改变j值,并且这个j值会被Myclass的所有实例共享 } }

static final static-final变量初始化机制

static变量在类加载的时候就会赋值,如果是static int a;则会在静态区给一个初始值0,之后可以修改,不能通过构造方法或非静态块来进行初始化,从设计角度来考虑,如果可以通过构造方法或非静态块来进行初始化,那每new一个对象都会对静态的常量进行再一次的赋值操作,也就是说修改它的值,

final变量在实例化的时候赋值即可,类加载的时候不会赋初始值,final int a;是个空final必须要实例化的时候赋值才能使用

例子

public class testmemberinnerclass { private final int a;//空final private static int b; private static final int c;//final修饰的不会初始赋值 static { c=0; } public testmemberinnerclass(int j,int l){ a=j; System.out.println("构造a:"+a); b=l; System.out.println("构造b:"+b); } public class innerclass { void m2_inner(int i, int k) { b = k; System.out.println("inner class a:" + a); System.out.println("inner class b:" + b); } } public static void main(String args[]) { System.out.println(""+b); System.out.println("对象outer1"); testmemberinnerclass outer = new testmemberinnerclass(10,11); innerclass inner = outer.new innerclass();// 必须通过包含内部类的外部类去访问内部类 inner.m2_inner(4, 5); System.out.println("对象outer2"); testmemberinnerclass outer1 = new testmemberinnerclass(20,21); innerclass inner1 = outer1.new innerclass();// 必须通过包含内部类的外部类去访问内部类 inner1.m2_inner(4, 5); } }

结果:

0 对象outer1 构造a:10 构造b:11 inner class a:10 inner class b:5 对象outer2 构造a:20 构造b:21 inner class a:20 inner class b:5

转载请注明原文地址: https://www.6miu.com/read-37947.html

最新回复(0)