static,final,static-final

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

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











  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值