疯狂java学习笔记之面向对象(八) - static和final
一、static:
1、static是一个标识符:
- 有static修饰的成员表明该成员是属于类的;
- 没有static修饰的成员表明该成员是属于实例/对象的。
2、static修饰的成员(Field、方法、初始化块),与类共存亡;static修饰的成员建议总是通过类名来访问,虽然它也可以通过实例来访问(实质也是通过类来访问的),所以平时若在其他程序中见到通过实例/对象来访问static成员时,可以直接将实例/对象 替换成类名;
3、程序都是先有类再有对象的,有可能出现有类但没有实例/对象的情况,反过来绝对不可能出现有实例/对象却没有类的现象。
4、类加载时会把属于类的Field存放到永生代堆内存中。
规则:
A、static修饰的成员不允许访问非static成员,非static成员可以访问static成员;
B、this引用、super都丕允许出现在static成员中;
C、若Field是实例/对象的,相当于前面省略了this. , 若Field是类的则相当于前面省略了类名.
注意点:若自己写程序永远都不要使用对象/实例去调用static修饰的方法、Field,若看到其他程序出现实例/对象去调用static修饰的方法、Field,我们阅读时则先把对象换成类名.
1 public class TestStatic{ 2 private int age; 3 private String name; 4 private static String gender; 5 private double weight; 6 7 public void test(String name){ 8 System.out.println("他/她叫: " + name); 9 } 10 11 public static void main(String[] args){ 12 TestStatic ts = new TestStatic(); 13 ts.test("小猴子"); 14 //通过对象ts来访问static成员,可以替换成类名.gender 15 //因为gender是string引用变量且属于成员变量,若程序员没给它赋初始值,系统会默认给个null值它 16 System.out.println(ts.gender); 17 System.out.println(TestStatic.gender); 18 } 19 }
1 public class TestStatic2{ 2 static int count = 99; 3 int age; 4 { 5 age = 22; 6 test(); 7 } 8 9 static{ 10 test(); 11 //age = 13; //static成员不能访问非static成员 12 } 13 14 public void way(){ 15 System.out.println("age值为: " + age); 16 } 17 18 public static void test(){ 19 //static方法引用了非static修饰的age,报错 20 //System.out.println("age的值为: " + age); 21 System.out.println("~~这是一个test方法~~"); 22 } 23 24 public static void main(String[] args){ 25 //定义了一个t2引用变量但t2并未指向任何对象 26 TestStatic2 t2 = null; 27 TestStatic2 t3 = new TestStatic2(); 28 //对于static修饰的Field、方法,直接打印时相当于前面省略了类名 29 System.out.println(count); //t2.count 30 //成员变量前必须有主调对象且有static修饰的方法不能直接访问没有static修饰的变量 31 System.out.println(t3.age); //t3.age; 32 } 33 }
二、final:
final作为一个修饰符,只能修饰:变量、方法和类。
1、final修饰变量
--final修饰的变量只能被赋值一次且赋值后不可改变。
A、final修饰成员变量:
Java成员变量默认可以由系统执行初始化,程序员可以不指定初始化,但final修饰的成员变量必须由程序员执行初始化
[原因]:如果final修饰的成员变量由系统执行初始化,那它的值只能是0、0.0、null、false、\u0000,且还不能改变,那么该变量则会变得毫无价值
若final修饰【实例变量】,可以在以下3个地方指定初始值:
①、定义时指定初始值;
②、初始化块中指定初始值;
③、构造器中指定初始值。
注意:final修饰的变量只能指定一次初始值且普通方法是不允许为final实例变量赋值的。
1 public class TestFinal{ 2 //final修饰实例变量必须指定初始值且只能在定义时、初始化块、构造器中指定。 3 final int age = 20; 4 final double weight; 5 /* 6 {final修饰的变量只能被赋值一次。 7 weight = 150; 8 }*/ 9 10 { 11 System.out.println("~~实例初始化块~~"); 12 } 13 14 public TestFinal(){ 15 weight = 140; 16 } 17 18 /* 普通方法不能为final修饰的变量赋值 19 public void setWeight(){ 20 this.weight = weight; 21 }*/ 22 23 public static void main(String[] args){ 24 TestFinal tf = new TestFinal(); 25 //实例变量必须拥有主调者 26 System.out.println(tf.weight); 27 } 28 }
若final修饰【类变量】,只可以在以下两个地方指定初始值:
①、定义时指定初始值;
②、类初始化块中指定初始值。
B、final修饰局部变量:
Java的局部变量默认就必须由程序员来指定初始值。
final修饰局部变量后,只有【一个变化】:一旦赋值后就不能再改变了。
1 public class TestFinal3{ 2 public static void main(String[] args){ 3 final int age; 4 age = 12; 5 System.out.println(age); 6 //final修饰age后,age只能赋值一次,否则报错"可能已分配变量age" 7 //age = 22; 8 //System.out.println(age); 9 } 10 }
C、final修饰的变量,它会被执行“宏替换”。如果final修饰的变量,可以【在编译的时候就确定】它的值,那么这个【变量就不存在】“宏替换” -- 就是查找、替换
1 public class FinalConstant { 2 public static void main(String[] args) { 3 String s1 = new String("疯狂java"); 4 String s2 = new String("疯狂java"); 5 System.out.println(s1 == s2); //false 6 7 //JVM会把所有用过的String对象进行缓存 8 String s3 = "fkjava.org"; 9 String s4 = "fkjava.org";//第二次用的是缓存中的fkjava.org对象 10 System.out.println(s3 == s4); //true 11 12 //由于+前后的值都是"直接量",可以直接计算 13 String s5 = "疯狂" + "软件"; 14 //在编译的时候,编译器已经把"+运算"计算出来,由于+前后的值都是"直接量",可直 //接计算 15 String s6 = "疯狂软件" ;//JVM在编译时就自动去掉+号 16 //s5、s6两个引用变量是否相等【必须指向同一个对象才相等】。 17 System.out.println(s6 == s5); //true 18 19 String s7 = "疯狂"; 20 String s8 = "java"; 21 //由于s7、s8都是变量,他们的值只有在运行时才能确定下来 22 //因此s9、s10的值只能在运行是动态的确定,都不会缓存,因此无法直接使用缓存中的值 23 String s9 = s7 + s8; 24 String s10 = s7 + s8; 25 System.out.println(s9 == s10); 26 27 /* 28 final String s11 = "fkjava"; 29 final String s12 = ".org"; 30 String s13 = s11 + s12; 31 String s14 = s11 + s12; 32 System.out.println(s13 == s14); //true */ 33 34 // final修饰的变量,【声明时就指定了初始值】,但他们的初始值在编译时不能确定, //所以不能执行宏替换,所以s11、s12只有在运行时才能确定 35 final String s11 = s9; //s11的字符序列是:疯狂java 36 final String s12 = s10;//s12的字符序列是:疯狂java 37 String s13 = s11 + s12; 38 String s14 = s11 + s12; 39 System.out.println(s13 == s14); //false 40 41 //final修饰的变量,【声明时就指定了初始值】,【而且初始值在编译就可以确定】 42 //那么这个变量就不存在,s15/s16会执行“宏替换”,也就是这两个变量根本就不存 //在,所有出现s15的地方都会替换成"fkjava",s16替换成".org" 43 //final String s15 = "fkjava"; 44 //final String s16 = ".org"; 45 /*String s17 = s15 + s16; 46 String s18 = s15 + s16;*/ 47 48 String s17 = "fkjava" + ".org"; 49 String s18 = "fkjava" + ".org"; 50 System.out.println(s17 == s18); //true 51 52 } 53 }
3、final修饰方法:
final修饰的方法不能被重写@Override;
好处:禁止父类的方法被重写,避免破坏父类方法
注意点:final与private结合没有实际意义,两者存一即可(private本身就不能被重写)。
4、final修饰类:
final类不能有子类,由于它不能有子类,所以它的方法能可以被更好的保护,典型的final类有:String、System、Math和包装类。
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。