1 Java 中的 static 使用之静态变量
1.1 使用场景:
大家都知道,我们可以基于一个类创建多个该类的对象,每个对象都拥有自己的成员,互相独立。然而在某些时候,我们更希望该类所有的对象共享同一个成员。此时就是 static 大显身手的时候了!!
Java 中被 static 修饰的成员称为静态成员或类成员。它属于整个类所有,而不是某个对象所有,即被类的所有对象所共享。静态成员可以使用类名直接访问,也可以使用对象名进行访问。当然,鉴于他作用的特殊性更推荐用类名访问~~
使用 static 可以修饰变量、方法和代码块。
本小节,我们先认识一下静态变量。
例如,我们在类中定义了一个 静态变量 hobby ,操作代码如下所示:
要注意哦:静态成员属于整个类,当系统第一次使用该类时,就会为其分配内存空间直到该类被卸载才会进行资源回收!~~
2 Java 中的 static 使用之静态方法
静态变量和实例变量的区别?
在语法定义上的区别:静态变量前要加static关键字,而实例变量前不加。
在程序运行时的区别:实例变量属于某个对象的属性,必须创建了实例对象,其中的实例变量才会被分配空间,才能使用这个实例变量。
静态变量不属于某个实例对象,而是属于类,所以也称为类变量,只要程序加载了类的字节码文件,不用创建任何实例象,静态变量就会被分 配空间,静态变量就可以被使用了。
总之,实例变量必须创建对象后才可以通过这个对象来使用,静态变量则可以直接使用类名来引用。
是否可以从一个static方法内部发出对非static方法的调用?
不可以。因为非static方法要与对象关联在一起,必须创建一个对象后,才可以在该对象上进行方法的调用,而static方法调用时不需要创建对象,可以直接调用。也就是说,一个static方法被调用时,可能还没有创建任何实例对象,所以,一个static方法内部不可以发出对非static方法的调用。
Integer与int的区别?
int是java提供的8种基本数据类型之一。Java为每个原始类型提供了封装类,Integer是Java为int提供的包装类。int的默认值是0,而Integer的默认值是null,即Integer可以区分出来未赋值和值为0的区别,int则无法表达出来未赋值的情况,例如想要表达出没有参加考试和考试成绩为0的区别,则只能用Integer。
详见http://www.cnblogs.com/dazuihou/p/3567821.html
Math.round(11.5)等于多少?Math.round(-11.5)等于多少?
Math类中提供了三种与取整有关的方法:ceil、floor、round。这些方法的作用与他们的英文名称的含义相对应,ceil的英文意思是装天花板,该方法就表示向上取整。floor的英文意思是地板,该方法就表示向下取整。至于round方法,他表示“四舍五入”,算法为Math.floor(x+0.5f),即将原来的数字加上0.5,之后再向下取整。所以,Math.round(11.5)的结果为12,Math.round(-11.5)的结果为-11。
下面代码有什么不妥之处?
1.if(username.equals("zxx")){}
2.int x=1; return x==1?true:false;
答:1.应该先判断username是否是null;如果是null,则会出现空指针异常。
改为:if("zxx".equals(username)){}
2.x==1本身就返回boolean型,再用三元操作符判断true和false多此一举。
改为:return x==1;
请说出作用域public,private,protected以及不写时的区别
作用域 | 同一类 | 同一包 | 子类中 | 不同包 |
public | √ | √ | √ | √ |
protected | √ | √ | √ | × |
defualt(friendly) | √ | √ | × | × |
private | √ | × | × | × |
public:接口访问权限
protected:继承访问权限
default:包访问权限
private:你无法访问(除了包含该成员的类以外,其他任何类都无法访问这个成员)
1 public class Baset { 2 private String baseName = "base"; 3 // 构造方法 4 public Baset() { 5 callName(); 6 } 7 // 成员方法 8 public void callName() { 9 // TODO Auto-generated method stub 10 System.out.println("basename:" + baseName); 11 } 12 //静态内部类 13 static class Sub extends Baset {//static必须写在开头 14 // 静态字段 15 private String baseName = "sub"; 16 public Sub() { 17 callName(); 18 } 19 // 重写父类的方法 20 public void callName() { 21 System.out.println("subname:" + baseName); 22 } 23 } 24 25 public static void main(String[] args) { 26 Baset base = new Sub(); 27 } 28 }
求这段程序的输出。
解答此题关键在于理解和掌握类的加载过程以及子类继承父类后,重写方法的调用问题:
一、从程序的执行顺序去解答:
1.编译;当这个类被编译通知后,会在相应的目录下生成两个.class 文件。一个是 Base.class,另外一个就是Base$Sub.class。这个时候类加载器将这两个.class 文件加载到内存
2、Base base= new Sub():
声明父类变量base对子类的引用,JAVA类加载器将Base,Sub类加载到JVM(Java虚拟机);
3、JVM为Base,Sub 的的成员开辟内存空间
此时,Base 和Sub类中的值为null;
4、new Sub();
这个时候会调用Sub类的隐式构造方法,
Sub的构造方法本质为:
public Sub(){
super();// 调用父类的构造方法。必须在构造方法中的第一行,为什么呢?这是因为在一些程序的升级中,要兼容旧版本的一些功能,父类即原先的一些初始化信息也要保证 //被执行到,然后执行当前
baseName = "sub";//子类字段初始化
}
new Sub()执行到super()这行代码也就是跑到父类中去执行了,我们跳转到父类中的无参构造方法中执行,最后执行Sub()中的baseName = "sub"
5、public Base() ;
父类无参构造方法的本质为:
public Base(){
baseName= "base";//父类字段初始化
callName();
}
即将父类的baseName赋值为“base”,赋值后调用callName();
6、callName()方法在子类中被重写,因此调用子类的callName(),子类的callName方法执行,打印输出的是子类的baseName 字段的值,而这个时候子类的构造函数中字段的赋值还未执行。
7、父类的构造函数执行完毕,这个时候又回到子类当中,从super()的下一行继续执行,这个时候才为子类字段baseName 分配好存储空间,随后为其赋值:
可见,在baseName = "sub"执行前,子类的callName()已经执行,所以子类的baseName为默认值状态null;
二、另写两个程序,进行更具体的分析
1、第一个程序:
1 public class InitialOrderTest { 2 // 变量 3 public String field = "变量"; 4 // 静态变量 5 public static String staticField="静态变量"; 6 //父类静态方法 7 public static void Order(){ 8 System.out.print("父类静态方法"); 9 System.out.println("staticField:"+staticField); 10 } 11 12 // 静态初始代码块 13 static{ 14 System.out.println("静态初始化块"); 15 System.out.println("staticField:"+staticField); 16 } 17 // 初始化代码块 18 { 19 System.out.println("初始化代码块"); 20 System.out.println("field:"+field); 21 } 22 // 构造函数 23 public InitialOrderTest(){ 24 System.out.println("构造器"); 25 26 } 27 28 public static void main(String[] args) { 29 System.out.println("-----[[-------"); 30 System.out.println(InitialOrderTest.staticField); 31 InitialOrderTest.Order(); 32 System.out.println("------]]------"); 33 InitialOrderTest i = new InitialOrderTest(); 34 System.out.println("-----[[-------"); 35 System.out.println(InitialOrderTest.staticField); 36 InitialOrderTest.Order(); 37 System.out.println("------]]------"); 38 39 } 40 }
执行结果为:
第一个程序总结:
1)、java中的块分为静态块(static{})和非静态块({}),这两种的执行是有区别的:
非静态块的执行时间是:在执行构造函数之前。 静态块的执行时间是:class文件加载时执行。
static类型的属性也是在类加载时执行的。
2)、可见Java类的实例变量初始化的过程:
static类型的成员属性执行,静态块(static{})按顺序执行,然后非静态成员变量初始化,非静态代码块({})执行,最后执行构造方法。
static类型与static块按先后顺序执行。
1 public class BaseTest { 2 // 父类变量 3 private String baseName = "base"; 4 // 父类静态变量 5 private static String staticField = "父类静态变量"; 6 // 父类静态方法 7 public static void Order() { 8 System.out.println("父类静态方法-"); 9 System.out.println("staticField:" + staticField); 10 } 11 // 父类静态初始代码块 12 static { 13 System.out.println("父类静态初始化代码块-"); 14 System.out.println("staticField:" + staticField); 15 } 16 // 初始化代码块 17 { 18 System.out.println("父类非静态初始化代码块-"); 19 System.out.println("baseName:" + baseName); 20 } 21 // 构造函数 22 public BaseTest() { 23 System.out.println("父类构造方法"); 24 callName(); 25 } 26 // 成员方法 27 public void callName() { 28 System.out.println("父类callName方法-"); 29 System.out.println("baseName:" + baseName); 30 } 31 32 // 静态内部类 33 static class Sub extends BaseTest { 34 // 子类变量 35 private String baseName = "sub"; 36 // 子类 静态变量 37 private static String staticField = "子类静态变量"; 38 39 // 子类静态方法 40 public static void Order() { 41 System.out.println("子类静态方法-"); 42 System.out.println("staticField:" + staticField); 43 } 44 45 // 子类静态初始化代码块 46 static { 47 System.out.println("子类静态初始化代码块-"); 48 System.out.println("staticField:" + staticField); 49 } 50 // 子类非静态初始化代码块 51 { 52 System.out.println("子类非静态初始化代码块-"); 53 System.out.println("baseName:" + baseName); 54 } 55 56 public Sub() { 57 System.out.println("子类构造方法"); 58 callName(); 59 } 60 61 public void callName() { 62 System.out.println("子类重写父类callName方法-"); 63 System.out.println("baseName:" + baseName); 64 } 65 } 66 67 public static void main(String[] args) { 68 69 BaseTest b = new Sub(); 70 71 System.out.println("-----[[-------"); 72 Sub.Order(); 73 System.out.println(Sub.staticField); 74 System.out.println(BaseTest.staticField); 75 BaseTest.Order(); 76 System.out.println("------]]------"); 77 78 } 79 }