static、final的个人详解

1.我觉得在以下几种情况下使用static

1).只想用一个存储区域来保存一个特定的数据——无论要创建多少个对象,甚至根本不创建对象。 

2).我们需要一个特殊的方法,它没有与这个类的任何对象关联。也就是说,即使没有创建对象,也需要一个能调用的方法。

3).static可以用来修饰类的成员方法、类的成员变量,另外可以编写static代码块来优化程序性能


2.static方法就是没有this的方法,在static方法内部不可以调用非static的方法,反过来是可以的。而且可以在没有任何对象创建的情况下,通过类名调用,这正是static的主要用途。一句话概括就是:方便在没有对象的情况下调用。


3.为什么static方法中不能调用非static的方法呢?

这是因为:static方法是要与对象关联在一起的,必须创建一个对象后,才可以在该对象上进行方法调用,而static方法调用时不需要创建对象,可以直接调用。也就是说,当一个static方法被调用时,可能还没有创建任何实例对象,如果从一个static方法中发出对非static方法的调用,那个非static方法是关联到哪个对象上的呢?这个逻辑无法成立,所以在静态方法中不能访问类的非静态成员变量和非静态成员方法,因为非静态成员方法/变量都是必须依赖具体的对象才能够被调用。



4.我们最常见的static方法就是main()方法,因为程序需要在没有对象创建的情况下就运行main()方法。


5.static变量也称作静态变量,静态变量和非静态变量的区别是:静态变量被所有的对象所共享,在内存中只有一个副本,它当且仅当在类初次加载时会被初始化。而非静态变量是对象所拥有的,在创建对象的时候被初始化,存在多个副本,各个对象拥有的副本互不影响。


6.static关键字还有一个比较关键的作用就是 用来形成静态代码块以优化程序性能。static块可以置于类中的任何地方,类中可以有多个static块。在类初次被加载的时候,会按照static块的顺序来执行每个static块,并且只会执行一次。

为什么说static块可以用来优化程序性能,是因为它的特性:只会在类加载的时候执行一次。

class Person{
    private Date birthDate;
    public Person(Date birthDate) {
        this.birthDate = birthDate;
    }   
    boolean isBornBoomer() {
        Date startDate = Date.valueOf("1946");
        Date endDate = Date.valueOf("1964");
        return birthDate.compareTo(startDate)>=0 && birthDate.compareTo(endDate) < 0;
    }
}

每次isBornBoomer被调用的时候,都会生成startDate和birthDate两个对象,造成了空间浪费,如果改成这样效率会更好:

class Person{
    private Date birthDate;
    private static Date startDate,endDate;
    static{
        startDate = Date.valueOf("1946");
        endDate = Date.valueOf("1964");
    }
    public Person(Date birthDate) {
        this.birthDate = birthDate;
    }   
    boolean isBornBoomer() {
        return birthDate.compareTo(startDate)>=0 && birthDate.compareTo(endDate) < 0;
    }
}

因此,很多时候会将一些只需要进行一次的初始化操作都放在static代码块中进行。


7.对于静态方法来说没有this,但是,在非静态方法中,也可以通过this来访问静态成员变量。

public class MyTest {
	static int value = 20;
	public static void main(String[] args) {
		new MyTest().njjMethod();
	}
	private void njjMethod() {
		int value = 10;
		System.out.println(this.value); // 20
		System.out.println(value);      // 10
	}
}

静态成员变量虽然独立于对象,但是不代表不可以通过对象去访问,所有的静态方法和静态变量都可以通过对象访问(只要访问权限足够)。


8.static是不允许用来修饰局部变量。不要问为什么,这是Java语法的规定。


9.常见面试题1:

public class MyTest extends Base {
	static {
		System.out.println("MyTest static");
	}

	public MyTest() {
		System.out.println("MyTest constructor");
	}

	public static void main(String[] args) {
		System.out.println("mytest main()");
		new MyTest();
	}
}

class Base {
	static {
		System.out.println("base static");
	}

	public Base() {
		System.out.println("base constructor");
	}
}
输出结果为:

base static
MyTest static
mytest main()
base constructor
MyTest constructor
首先,执行MyTest的main()方法,因为这个方法是程序的入口,但是在执行main方法之前,首先要加载MyTest类,但是加载MyTest类的时候,发现他加成的是Base类,所以会去先加载Base类。在执行Base类的时候,发现有static代码块,所以会先执行它,执行完Base之后,回到MyTest,发现MyTest也有代码块,这是就会执行MyTest的代码块,然后执行main方法。在main方法中,new一个当前的对象,类似于static代码块,首先会先去执行父类的构造器,然后再回来执行自身的构造器。


10.常见面试题2:

public class MyTest {
	Person person = new Person("MyTest"); 
	static {
		System.out.println("MyTest static"); // 1
	}

	public MyTest() {
		System.out.println("MyTest constructor"); // 6
	}

	public static void main(String[] args) {
		System.out.println("mytest main"); //2 
		new MyClass();
	}
}

class Person {
	static {
		System.out.println("person static"); // 4
	}

	public Person(String str) {
		System.out.println("Person " + str); // 5 mytest
						     // 7 myclass
	}
}

class MyClass extends MyTest {
	Person person = new Person("myclass");
	static {
		System.out.println("myclass static"); // 3
	}

	public MyClass() {
		System.out.println("myclass constructor"); // 8
	}
}

执行结果为:

MyTest static
mytest main
myclass static
person static
Person MyTest
MyTest constructor
Person myclass
myclass constructor

首先,运行MyTest,没有父类,就开始加载自身的static代码块,随后执行main方法中的new MyClass(),而此时MyClass类还没有被加载,所以需要先加载MyClass类。在加载MyClass的时候,发现,它继承的是MyTest类,而MyTest的static已经执行,所以不需要在执行,直接执行MyClass的static代码块就行了。加载完代码块之后,会通过构造器来生成对象,需要先执行父类的构造器,但是在调用构造器生成对象之前,需要先初始化类的成员变量,然后从MyTest中调用Person,会先调用Person中的static代码块,然后执行person的构造方法,生成person对象,然后执行父类MyTest的构造器,紧接着生成MyClass的对象, 同样需要先初始化成员变量,在MyClass中调用person,由于person中的static代码块已经加载过一次,所以不会在加载,只需要再生成一个person对象即可。最后才执行MyClass的构造器,生成对象。


11.Android static 静态成员变量的使用误区

static 修饰的静态变量,使用很方便,在不同的类和包中都可以使用,在虚拟机中单独占用内存,没错,这些都是它们的优点。

比如说,一个用户信息user,如果我们定义成static user u = new user();这样就不会有太大的问题,但是如果static user u;这样定义的话,就很容易出现空指针的问题。

那么应该如何保存登录或者全局的信息呢?根据Google官方的推荐以及百度到的各位大神的推荐,我们应该尽量使用继承自Application的自定义类,在我们继承的类中定义需要全局使用的变量,并通过getApplicationContext()来获取和保存相关的变量即可。实例:

package com.jony.bitmaptest;
 
import android.app.Application;
import android.os.Handler;
 
public class MyAplication extends Application{
     // 引发异常:在一些不规范的代码中经常看到Activity或者是Service当中定义许多静态成员属性。这样做可能会造成许多莫名其妙的null pointer异常。
 
     // 异常分析:Java虚拟机的垃圾回收机制会主动回收没有被引用的对象或属性。在内存不足时,虚拟机会主动回收处于后台的Activity或Service所
    // 占用的内存。当应用再次去调用静态属性或对象的时候,就会造成null pointer异常
 
    // 解决异常:Application在整个应用中,只要进程存在,Application的静态成员变量就不会被回收,不会造成null pointer异常
    private static final int MSG = 0X1;
    private Handler mHandler = new Handler(){
          public void handleMessage(android.os.Message msg) {
               switch (msg.what) {
                    case MSG:
                    break;
                    default:
                    break;
              }
         };
   };
   private String action;
   private String username;
   private String password;
   @Override
   public void onCreate() {
        // TODO Auto-generated method stub
        super.onCreate();
   }
   public String getUsername() {
        return username;
   }
   public void setUsername(String username) {
        this.username = username;
   }
   public String getPassword() {
        return password;
   }
   public void setPassword(String password) {
        this.password = password;
   }
   public String getAction() {
        return action;
   }
   public void setAction(String action) {
        this.action = action;
   }
   public Handler getHandler(){
       return mHandler;
   }
}
在Activity和Service中的是使用方法:

MyApplication application = (MyApplication) this.getApplicationContext();


12.final类不能被继承,没有子类,final类中的方法默认是final的。

 final方法不能被子类的方法覆盖,但可以被继承。

 final成员变量表示常量,只能被赋值一次,赋值后值不再改变。

 final不能用于修饰构造方法。


13.final修饰类中的属性和变量

无论属性是基本数据类型还是引用数据类型,final所起的作用都是变量里面存放的“值”不能变。这个值,对于基本数据类型来说就是实实在在的值,如1、"str"。

而对于引用数据类型来说,里面放的是个地址,所以final修饰的引用数据类型变量是值它的地址不能变,而地址所指向的对象或者数组的内容是可以变的。

例如:final StringBuffer a=new StringBuffer("immutable"); 在有上一句的前提下,执行下一句a=new StringBuffer("");会报错,因为这是在改变a指向的对象,由于

是final修饰的,此时,是不允许的,但是,a.append("aaa");是可以通过的,因为指向的对象没有改变,只是改变了内容。


14.关于final有一个有趣的现象:

public class Test2 {
	byte b1 = 1;
	byte b2 = 2;

	byte b3 = b1 + b2; // 无法通过
}
最后一句byte b3 = b1 + b2; 是无法通过的,根据提示,只需要把b3改为int类型,或者将b1 + b2 强制转换成byte就可以了。

这是因为,short,byte,char在运算的时候,自动转换成了int类型,所以,将int赋值给byte,是不对的。

此时,就用到了final了,只需要把b1 和 b2 前面加上final,就不会报错了。这就说明了之前说的,增加final之后,对象不会变,是byte就是byte,不会因为运算而自动变成int了


15.final方法:

如果一个类不允许其子类覆盖某个方法,则可以把这个方法声明为final方法。

使用final方法原因有二:

1).把方法锁定,防止任何继承类修改它的意义和实现。

2).高效。编译器在遇到final方法时候会转入到内嵌机制,大大提高执行效率。


16.final成员变量初始化,在使用成员之前,要确保他们已经初始化。可以在三个地方进行初始化:

1).声明定义的时候初始化

2).在构造函数中初始化

3).非静态初始化代码块或者static代码块中。


17.定义方法中的参数为final,对于基本类型的变量,这样做并没有什么实际意义,因为基本类型的变量在调用方法时是传值的,也就是说你可以在方法中更改这个参数变量而

不会影响到调用语句,然而对于对象变量,却显得很实用,因为对象变量在传递时是传递其引用,这样你在方法中对对象变量的修改也会影响到调用语句中的对象变量,当你在

方法中不需要改变作为参数的对象变量时,明确使用final进行声明,会防止你无意的修改而影响到调用方法。


参考博客:

http://my.oschina.net/moziqi/blog/340157

http://www.cnblogs.com/dolphin0520/p/3799052.html

http://491823151.iteye.com/blog/1052895

http://blog.csdn.net/axman/article/details/1460544







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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值