标签:set turn tail src ant run 独立 interrupt 本地
转自:http://blog.csdn.net/manyizilin/article/details/51926230#L42
修饰符:
像其他语言一样,Java可以使用修饰符来修饰类中方法和属性。主要有两类修饰符:
访问修饰符:default, public , protected, private
非访问修饰符:final, abstract, strictfp
修饰符一般使用在一个语句的前端,例:
访问修饰符
Java中,可以使用访问控制符来保护对类、变量、方法和构造方法的访问。Java支持4种不同的访问权限。
默认的,也称为 default,在同一包内可见,不使用任何修饰符。
私有的,以 private 修饰符指定,在同一类内可见。
共有的,以 public 修饰符指定,对所有类可见。
受保护的,以 protected 修饰符指定,对同一包内的类和所有子类可见。
Java中类的修饰符有以下几种:private 、default(package)、protect、public,其范围如下表:
范围 | private | default | protected | public |
同一类 | √ | √ | √ | √ |
同一包中的类 | √ | √ | √ | |
同一包中的类、不同包中的子类 | √ | √ | ||
所有 | √ |
使用默认访问修饰符声明的变量和方法,对同一个包内的类是可见的。接口里的变量都隐式声明为public static final,而接口里的方法默认情况下访问权限为public。
私有访问修饰符是最严格的访问级别,所以被声明为private的方法、变量和构造方法只能被所属类访问,并且类和接口不能声明为private。
被声明为public的类、方法、构造方法和接口能够被任何其他类访问。
如果几个相互访问的public类分布在不同的包中,则需要导入相应public类所在的包。由于类的继承性,类所有的公有方法和变量都能被其子类继承。
被声明为protected的变量、方法和构造器能被同一个包中的任何其他类访问,也能够被不同包中的子类访问。
Protected访问修饰符不能修饰类和接口,方法和成员变量能够声明为protected,但是接口的成员变量和成员方法不能声明为protected。
子类能访问Protected修饰符声明的方法和变量,这样就能保护不相关的类使用这些方法和变量。
请注意以下方法继承的规则:
父类中声明为public的方法在子类中也必须为public。
父类中声明为protected的方法在子类中要么声明为protected,要么声明为public。不能声明为private。
父类中声明为private的方法,不能够被继承。
为了实现一些其他的功能,Java也提供了许多非访问修饰符。
static修饰符,用来创建类方法和类变量。
Final修饰符,用来修饰类、方法和变量,final修饰的类不能够被继承,修饰的方法不能被继承类重新定义,修饰的变量为常量,是不可修改的。
Abstract修饰符,用来创建抽象类和抽象方法。
Synchronized和volatile修饰符,主要用于线程的编程。
Static关键字用来声明独立于对象的静态变量,无论一个类实例化多少对象,它的静态变量只有一份拷贝。 静态变量也被成为类变量。局部变量不能被声明为static变量。
静态方法:
Static关键字用来声明独立于对象的静态方法。静态方法不能使用类的非静态变量。静态方法从参数列表得到数据,然后计算这些数据。(这就是访问权限的问题了)。
被static
修饰符修饰的成员方法和成员变量是独立于该类的任何对象的,可以被所有的类所共享。应为在加载(还没有实例化该类之前),JVM就已经为静态方法和静态变
量分配内存空间。到时候只要使用类名去访问就可以了。被public
修饰的static成员变量和成员方法本质是全局变量或者是全局方法。任何一个类都可以同个类名访问内部和成员变量和成员方法
static代码块
也叫做静态代码块,独立于类成员的代码块。在一个类中可以有多个静态代码块,位置可以任意,它不再任何方法体内,JVM加载类的时候,会自动执行静态代码块(记住:在加载类的时候就已经执行了,不用等待实例化类)。如果是由对各静态代码块,那么JVM就会按照这些静态代码块出现的顺序执行它们。每个静态代码块自会执行一次。(就是这个程序从开始运行到结束只会执行一次)。
执行结果:
main静态代码块
main程序
静态代码块0
静态代码块1
StaticTest
解释:程序执行后,先加载 HellowJava 类 ,这时候执行这个类中的静态代码块,加载完毕那个后直接执行 mian() 方法,
按顺序先执行 System.out.println("main程序");
再加载StaticTest 类,这时候执行StaticTest中的静态代码块,并且按顺序执行这些代码块
最后实例化这个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 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成员变量进行初始化,则不要在初始化之前就访问该成员的值。
(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和final修饰,如果这个类包含抽象方法,那么这个类一定要声明为抽象类,否则出现错误。
抽象类的内部可以包含抽象方法和非抽象方法。
抽象类如下:
抽象方法:
抽象方法是一种没有任何实现的方法,具体的实现依靠子类方法实现。该方法也不可以声明为final 和static
任何继承了抽象类的子类必须实现父类的中抽象方法,除非这个子类也是抽象类。
如果一个类中包含抽象方法,那么这个类必须是抽象类,一个抽象类中也可以不包含任何的抽象方法。
例:
和接口(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修饰符可以应用于四个访问修饰符。
实例:
参考详情:
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 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 |
/*静态代码块的测试*/
public class SynchronizedClass implements Runnable {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
SynchronizedClass run = new SynchronizedClass();
Thread t1 = new Thread(run,"aaa");
Thread t2 = new Thread(run,"bbb");
t1.start();
t2.start();
}
@Override
public void run() {
// TODO Auto-generated method stub
synchronized(this){
for(int i = 0;i<3;i++){
System.out.println(Thread.currentThread().getName()+" "+i);
}
}
}
}
/*
* 结果:
aaa 0
aaa 1
aaa 2
bbb 0
bbb 1
bbb 2
* */
/*
* 然而,当一个线程访问object的一个synchronized(this)同步代码块时,
* 另一个线程仍然可以访问该object中的非synchronized(this)同步代码块。*/
//————————————————————————————————————————————————————————————————————————
public class SynchronizedClass2 {
public void test1(){
synchronized(this){
for(int i = 0;i<3;i++){
System.out.println(Thread.currentThread().getName()+" "+i);
}
}
}
public void tet2(){
for(int i = 0;i<3;i++){
System.out.println(Thread.currentThread().getName()+" "+i);
}
}
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
final SynchronizedClass2 run = new SynchronizedClass2();
Thread t1 = new Thread(new Runnable(){
@Override
public void run() {
// TODO Auto-generated method stub
run.test1();
}
},"a");
Thread t2 = new Thread(new Runnable(){
@Override
public void run() {
// TODO Auto-generated method stub
run.tet2();
}
},"b");
t1.start();t2.start();
}
}
/*结果 。每一次的结果可能都是不一样的
* a 0
a 1
b 0
a 2
b 1
b 2*/
//————————————————————————————————————————————————————————————————————
/*
* 当一个线程访问object的一个synchronized(this)同步代码块时,
* 其他线程对object中所有其它synchronized(this)同步代码块的访问将被阻塞
*
* 每个对象都只有一个锁,只有拿到了这个锁才可以访问这个对象中的同步代码块,
* 是否访问的是同一个同步代码块都需要拿到这个对象锁
* 非同步代码块可以任意访问
*
* 当有一个线程已经拿到这个锁的时候,另一个线程想要去访问这个对象中的不同于前一个线程访问的同步代码块时,
* 也需要等待前一个线程访问完成,释放对象锁才可以访问这个对象的同步代码块*/
public class SynchronizedClass3 {
public void test1(){
synchronized(this){
int i = 5;
while(i-->0){
System.out.println(Thread.currentThread().getName()+" "+i);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
public void test2(){
synchronized(this){
int i = 5;
while(i-->0){
System.out.println(Thread.currentThread().getName()+" "+i);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
/**
* @param args
*/
public static void main(String[] args) {
final SynchronizedClass3 run = new SynchronizedClass3();
// TODO Auto-generated method stub
Thread t1 = new Thread(new Runnable(){
@Override
public void run() {
// TODO Auto-generated method stub
run.test1();
}
});
Thread t2 = new Thread(new Runnable(){
@Override
public void run() {
// TODO Auto-generated method stub
run.test2();
}
});
t1.start();
t2.start();
}
}
/*
* 结果:
*
Thread-0 4
Thread-0 3
Thread-0 2
Thread-0 1
Thread-0 0
Thread-1 4
Thread-1 3
Thread-1 2
Thread-1 1
Thread-1 0
* */
//——————————————————————————————————————————————————————————————
/*
* 和实例3一样,同步代码块的原则到同步方法同样是适用的
* 当一个线程访问object的一个synchronized(this)同步代码块时,
* 其他线程对object中所有其它synchronized(this)同步代码块的访问将被阻塞
*
* 每个对象都只有一个锁,只有拿到了这个锁才可以访问这个对象中的同步代码块,
* 是否访问的是同一个同步代码块都需要拿到这个对象锁
* 非同步代码块可以任意访问
*
* 当有一个线程已经拿到这个锁的时候,另一个线程想要去访问这个对象中的不同于前一个线程访问的同步代码块时,
* 也需要等待前一个线程访问完成,释放对象锁才可以访问这个对象的同步代码块*/
public class SynchronizedClass4 {
public synchronized void test1(){
int i = 5;
while(i-->0){
System.out.println(Thread.currentThread().getName()+" "+i);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public synchronized void test2(){
int i = 5;
while(i-->0){
System.out.println(Thread.currentThread().getName()+" "+i);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
/**
* @param args
*/
public static void main(String[] args) {
final SynchronizedClass4 run = new SynchronizedClass4();
// TODO Auto-generated method stub
Thread t1 = new Thread(new Runnable(){
@Override
public void run() {
// TODO Auto-generated method stub
run.test1();
}
});
Thread t2 = new Thread(new Runnable(){
@Override
public void run() {
// TODO Auto-generated method stub
run.test2();
}
});
t1.start();
t2.start();
}
}
/*
* 结果:
*
Thread-0 4
Thread-0 3
Thread-0 2
Thread-0 1
Thread-0 0
Thread-1 4
Thread-1 3
Thread-1 2
Thread-1 1
Thread-1 0
* */
|
1、无论synchronized 关键字作用在方法上还是对象上,如果他作用的对象是非静态的那么它取得的锁是对象;如果作用在静态方法或者或者一个类,那么它取得的锁是类,该类的所有对象同一把锁。
2、每个对象只有一把锁(lock)与之相关联,谁拿到那把锁就可以运行这个对象控制的那段代码。
3、实现同步是要很大的系统开销的,有时候会造成死锁,尽可能避免无谓的同步控制。
在synchronized(this) 表示锁住的是this这个对象。
如果要实现同步,必须要锁同一个对象,就算是两个线程的锁一个是类,一个是类的实例(对象)例如:
结果:
d 2
c 2
c 3
d 4
c 5
d 6
d 7
c 8
d 9
c 10
上面的例子中,一个锁是Pig对象,一个锁是Pig类,这样也会出现访问混乱,不能达到同步的效果。
实现了Serilizable接口可以将不需要序列化的的属性前面加上 transient ,序列化对象的时候,不会吧这个属性序列化到指定的目的地。
(1)一旦变量被transient修饰,变量将不再是对象持久化的一部分,该变量内容在序列化后无法获得访问。
(2)transient关键字只能修饰变量,而不能修饰方法和类。注意,本地变量是不能被transient关键字修饰的。变量如果是用户自定义类变量,则该类需要实现Serializable接口。
(3)被transient关键字修饰的变量不再能被序列化,一个静态变量不管是否被transient修饰,均不能被序列化。
参考:http://www.cnblogs.com/lanxuezaipiao/p/3369962.html
Volatile 修饰的成员变量在每次被线程访问时,都强制从共享内存中重新读取该成员变量的值。而且,当成员变量发生变化时,会强制线程将变化值回写到共享内存。这样在任何时刻,两个不同的线程总是看到某个成员变量的同一个值。
一个volatile对象引用可能是null。
public class MyRunnable implements Runnable
{
private volatile boolean active;
public void run()
{
active = true;
while (active) // 第一行
{
// 代码
}
}
public void stop()
{
active = false; // 第二行
}
}
通常情况下,在一个线程调用 run() 方法(在 Runnable 开启的线程),在另一个线程调用 stop() 方法。 如果 第一行 中缓冲区的 active 值被使用,那么在第二行 的 active 值为 false 时循环不会停止。
但是以上代码中我们使用了 volatile 修饰 active,所以该循环会停止。
相关测试代码:
参考:http://blog.csdn.net/m13666368773/article/details/7513049
参考:http://www.runoob.com/java/java-modifier-types.html
参考:http://www.cnblogs.com/EvanLiu/archive/2013/06/13/3134776.html
参考:http://blog.csdn.net/zhandoushi1982/article/details/8458081
参考:http://www.cnblogs.com/lanxuezaipiao/p/3369962.html
参考: http://www.cnblogs.com/GnagWang/archive/2011/02/27/1966606.html
参考: http://blog.csdn.net/luoweifu/article/details/46613015
参考:http://blog.csdn.net/zhandoushi1982/article/details/8458081
标签:set turn tail src ant run 独立 interrupt 本地
原文地址:http://www.cnblogs.com/Berryxiong/p/6245858.html