Java的修饰符
Posted xyqing525
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java的修饰符相关的知识,希望对你有一定的参考价值。
转自:http://blog.csdn.net/manyizilin/article/details/51926230#L42
修饰符:
像其他语言一样,Java可以使用修饰符来修饰类中方法和属性。主要有两类修饰符:
访问修饰符:default, public , protected, private
非访问修饰符:final, abstract, strictfp
修饰符一般使用在一个语句的前端,例:
- public void Pig{
- int a = 1;
- protected String b = "b";
- private static final int c = 1;
- }
访问修饰符
Java中,可以使用访问控制符来保护对类、变量、方法和构造方法的访问。Java支持4种不同的访问权限。
默认的,也称为 default,在同一包内可见,不使用任何修饰符。
私有的,以 private 修饰符指定,在同一类内可见。
共有的,以 public 修饰符指定,对所有类可见。
受保护的,以 protected 修饰符指定,对同一包内的类和所有子类可见。
Java中类的修饰符有以下几种:private 、default(package)、protect、public,其范围如下表:
范围 | private | default | protected | public |
同一类 | √ | √ | √ | √ |
同一包中的类 | √ | √ | √ | |
同一包中的类、不同包中的子类 | √ | √ | ||
所有 | √ |
默认访问修饰符-不使用任何关键字
使用默认访问修饰符声明的变量和方法,对同一个包内的类是可见的。接口里的变量都隐式声明为public static final,而接口里的方法默认情况下访问权限为public。
私有访问修饰符-private
私有访问修饰符是最严格的访问级别,所以被声明为private的方法、变量和构造方法只能被所属类访问,并且类和接口不能声明为private。
- public class Pig{
- private int num = 1;
- public int getNum(){
- return num;
- }
- public void setNum(int num){
- this.num = num;
- }
- }
公有访问修饰符-public
被声明为public的类、方法、构造方法和接口能够被任何其他类访问。
如果几个相互访问的public类分布在不同的包中,则需要导入相应public类所在的包。由于类的继承性,类所有的公有方法和变量都能被其子类继承。
受保护的访问修饰符-protected
被声明为protected的变量、方法和构造器能被同一个包中的任何其他类访问,也能够被不同包中的子类访问。
Protected访问修饰符不能修饰类和接口,方法和成员变量能够声明为protected,但是接口的成员变量和成员方法不能声明为protected。
子类能访问Protected修饰符声明的方法和变量,这样就能保护不相关的类使用这些方法和变量。
访问控制和继承
请注意以下方法继承的规则:
-
父类中声明为public的方法在子类中也必须为public。
-
父类中声明为protected的方法在子类中要么声明为protected,要么声明为public。不能声明为private。
-
父类中声明为private的方法,不能够被继承。
非访问修饰符
为了实现一些其他的功能,Java也提供了许多非访问修饰符。
static修饰符,用来创建类方法和类变量。
Final修饰符,用来修饰类、方法和变量,final修饰的类不能够被继承,修饰的方法不能被继承类重新定义,修饰的变量为常量,是不可修改的。
Abstract修饰符,用来创建抽象类和抽象方法。
Synchronized和volatile修饰符,主要用于线程的编程。
Static修饰符
静态变量:
-
Static关键字用来声明独立于对象的静态变量,无论一个类实例化多少对象,它的静态变量只有一份拷贝。 静态变量也被成为类变量。局部变量不能被声明为static变量。
静态方法:
-
Static关键字用来声明独立于对象的静态方法。静态方法不能使用类的非静态变量。静态方法从参数列表得到数据,然后计算这些数据。(这就是访问权限的问题了)。
被static
修饰符修饰的成员方法和成员变量是独立于该类的任何对象的,可以被所有的类所共享。应为在加载(还没有实例化该类之前),JVM就已经为静态方法和静态变
量分配内存空间。到时候只要使用类名去访问就可以了。被public
修饰的static成员变量和成员方法本质是全局变量或者是全局方法。任何一个类都可以同个类名访问内部和成员变量和成员方法
static代码块
也叫做静态代码块,独立于类成员的代码块。在一个类中可以有多个静态代码块,位置可以任意,它不再任何方法体内,JVM加载类的时候,会自动执行静态代码块(记住:在加载类的时候就已经执行了,不用等待实例化类)。如果是由对各静态代码块,那么JVM就会按照这些静态代码块出现的顺序执行它们。每个静态代码块自会执行一次。(就是这个程序从开始运行到结束只会执行一次)。
- public class HellowJava {
- static{}
- public static void main(String[] arguments) {
- System.out.println("main程序");
- new StaticTest();
- }
- }
- class StaticTest{
- public StaticTest(){
- System.out.println("StaticTest");
- }
- static{
- System.out.println("静态代码块0");
- }
- static{
- System.out.println("静态代码块1");
- }
- }
执行结果:
main静态代码块
main程序
静态代码块0
静态代码块1
StaticTest
解释:程序执行后,先加载 HellowJava 类 ,这时候执行这个类中的静态代码块,加载完毕那个后直接执行 mian() 方法,
按顺序先执行 System.out.println("main程序");
再加载StaticTest 类,这时候执行StaticTest中的静态代码块,并且按顺序执行这些代码块
最后实例化这个StaticTest类(这时候就会调用构造方法)
- public class HellowJava {
- static{
- System.out.println("main静态代码块");
- }
- public static void main(String[] arguments) {
- System.out.println("main程序"<span style="color:#FF0000;">+StaticTest.a)</span>; //这里的就造成了 StaticTest 类的加载(就是静态代码块会执行)<pre name="code" class="html">StaticTest
new StaticTest(); }}
class StaticTest{
public StaticTest(){
System.out.println("StaticTest"); }
static{ a=1; System.out.println("静态代码块0"); }
static{ System.out.println("静态代码块1"); }
public static final int a ;
}
结果:
main静态代码块静态代码块0静态代码块1main程序1 StaticTest解释:本来以为static 修饰的代码都是会按顺序直接执行或者分配内存的。看来好像不是这样子。怎么说呢。从最后一行代码可以看到我把静态变量的定义放在了最后面,但是并没有出现 任何报错,说明了JVM记载的时候是首先加载静态变量,再加载静态代码块的。(个人理解,喜欢就喷吧)
static和final一块用表示什么
static final用来修饰成员变量和成员方法,可以理解为“全局常量”。
对于变量 :表示一旦给定值就不可以更改,并且可以通过类名来访问。
对于方法: 表示不可以覆盖,并且可以通过类名来访问。
声明静态方法的限制:
仅能调用其他的static方法;
仅能访问static 数据
不能以任何形式引用this 和super(和继承有关)
Final
Final方法
类中的Final方法可以被子类继承,但是不能被子类修改。
声明final方法的主要目的是防止该方法的内容被修改。
Final类
Final类不能被继承,没有类能够继承final类的任何特性。
Final修饰符
final变量能被显性的初始化,并且只可以初始化一次。被声明为final的对象不能指向不同的对象。但是final中的值是可以改变的。也就是说final中对象的引用不能够改变,但是里边的值可以改变。
例如: final Integer a =10; Integer b =20; 可以这样改变 a =11; 或 a =20; 但是不可以 a =b ;
Final修饰符通常和static修饰符一起使用来创建类常量。
final修饰的成员变量
(1)final修饰的成员变量一旦赋值后,不能被重新赋值。
(2)final修饰的实例Field,要么在定义该Field的时候指定初始值,要么在普通初始化块或构造器中指定初始值。但是如果在普通初始化块中为某个实例Field指定了初始值,则不能再在构造器中指定初始值。
(3)final修饰的类Field,要么在定义该Field的时候指定初始值,要么在静态代码块中定义初始值。
(4)如果在构造器或初始化块中对final成员变量进行初始化,则不要在初始化之前就访问该成员的值。
- class finalTest{
- final int a = 1; //直接赋值
- final String b ;
- {
- b = "b"; //在代码块中赋值
- //这个代码块块只有当实例化这个类的时候优先于静态方法执行,
- //和构造方法无关,实例化的时候都会去执行 //比构造函数先执行
- }
- final boolean c;
- public finalTest(){ //在构造函数中赋值
- c = false;
- }
- final static int d = 8; //直接赋值
- final static int e;
- static{
- e = 1; //在静态代码块中赋值
- }
- }
(1)系统不会对局部变量进行初始化。布局变量必须要显示初始化。所以final修饰的局部变量既可以在定义的时候指定默认值,也可以不指定默认值。
(2)final修饰形参的时候,不能赋值
final修饰基本数据类型变量和修饰引用类型变量的区别
final修饰基本数据类型的变量,一旦该变量赋值后,就不能被重新复制赋值了。
对于引用类型的变量,保存的只是引用,final修饰的应用类型的变量只是保证这个对象不改变,但是这个对象的内部内容是可以发生改变的。比如:
- final List<String> list = new ArrayList();
- list.add("a"); list.add("b");
再看:
- final int a = 1;
- a =2;
final 的宏变量
(1)final 的一个重要的用途就是宏变量,当定义final变量是就制定了初值,这个初值是在编译的时候就加载进来了。编译会把程序中所用到的该变量的地方替换成该变量的值。
public class FinalTest {
public static void main(String[] args){
final String name = "小明" + 22.0;
final String name1 = "小明" + String.valueOf(22.0);
System.out.println(name == "小明22.0");
System.out.println(name1 == "小明22.0");
}
}
结果:
true
false
final String name1 = "小明"+String.valueOf(22.0); 中调用了String类的方法,所以在编译的时候无法确定name1的值,所以name1不会当作是宏变量。
package cn.lsl;
public class FinalTest {
public static void main(String[] args){
String s1 = "小明";
String s2 = "小" + "明";
System.out.println(s1 == s2); //true
String str1 = "小";
String str2 = "明";
String s3 = str1 + str2;
System.out.println(s1 == s3); //false
//宏替换
final String str3 = "小";
final String str4 = "明";
String s4 = str3 + str4;
System.out.println(s1 == s4); //true
}
}
(1)Java会使用常量池管理直接使用过的字符串直接量。 String a = "Hellow" ; 那么字符串池会缓存一个字符串 “Hellow”,当执行String b = "Hellow",会直接让b 指向“Hellow” 这个字符串, 所以a == b ;是true
(2)String s3 = str1+str2;在编译时没有办法确定s3的值。
(3)String s4 = str3+str4;应为执行了宏变换,所以在编译的时候就已经确定了s4的值
用final修饰的方法不能被重写。用final修饰的类不能有子类。
不可变类
不可变类是指创建该类的实例后,该实例的Field是不可改变的。
如果创建自定义的不可变类,应该遵循如下规则
(1)使用private和final修饰符来修饰该类的Field。
(2)提供带参数的构造器,用于传入参数来初始化类里的Field。
(3)仅为该类的Field提供getter方法,不要为该类的Field提供setter方法。
(4)如果有必要,重写Object类的hashCode和equals方法。
Abstract修饰符
抽象类:
abstract修饰符不能用来实例化对象,声明这个抽象类的唯一目的是为了将来对这个类进行扩充。
一个类不能同时被abstract和final修饰,如果这个类包含抽象方法,那么这个类一定要声明为抽象类,否则出现错误。
抽象类的内部可以包含抽象方法和非抽象方法。
抽象类如下:
- abstract class CaraVan{
- private double price;
- private String model ;
- private String year;
- public abstract void setName(String name); //抽象方法
- public abstract String getName();
- }
抽象方法:
抽象方法是一种没有任何实现的方法,具体的实现依靠子类方法实现。该方法也不可以声明为final 和static
任何继承了抽象类的子类必须实现父类的中抽象方法,除非这个子类也是抽象类。
如果一个类中包含抽象方法,那么这个类必须是抽象类,一个抽象类中也可以不包含任何的抽象方法。
例:
- abstract class Animal{
- public abstract void run(); //抽象方法。
- }
- class Pig extends Animal{
- @Override
- public void run() {
- // TODO Auto-generated method stub
- //do ...
- }
- }
和接口(Interface)的区别。
1、相同点:
(1)都是抽象类,都是不能实例化。
(2)interface实现类及abstact class 的之类都必须实现已经声明的抽象方法。
2、不同点
(1)interface 的实现使用的是implements ,而abstract class 的实现使用的是extends.
(2)一个类可以实现多个interface但是只可以继承一个abstract class
(3)interface强调功能的实现,而abstract 强调所属的关系。
(4)实现显示不一样,interface的每个方法都是抽象方法,没有方法体,而abstract class 子类可以选择的实现这些方法(其他的可以在abstract class类中直接实现方法体)。
抽象类的这个选择有两点含义:
一是Abastract class中并非所有的方法都是抽象的,只有那些冠有abstract的方法才是抽象的,子类必须实现。那些没有abstract的方法,在Abstrct class中必须定义方法体。
二是abstract class的子类在继承它时,对非抽象方法既可以直接继承,也可以覆盖;而对抽象方法,可以选择实现,也可以通过再次声明其方法为抽象的方式,无需实现,留给其子类来实现,但此类必须也声明为抽象类。既是抽象类,当然也不能实例化。
(5)interface是完全抽象的。只能声明方法,权限也只能声明为public,不能定义方法体,也不可以实例化变量(都是 public static fianl 类型)
详细参考:http://blog.csdn.net/zhandoushi1982/article/details/8458081
Synchronized修饰符
Synchronized关键字声明的方法同一时间只能被一个线程访问。Synchronized修饰符可以应用于四个访问修饰符。
实例:
- public synchronized void setName(){
- //...
- }
参考详情:
http://www.cnblogs.com/GnagWang/archive/2011/02/27/1966606.html
http://blog.csdn.net/luoweifu/article/details/46613015
测试代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 java 循环变量 |