关键字this、super、final、static、synchronized及 中断线程的方法

22 篇文章 0 订阅
21 篇文章 1 订阅

一java中的this随处可见,用法也多,现在整理有四点:

1  this是指当前对象自己。 

当在一个类中要明确指出使用对象自己的的变量或函数时就应该加上this引用。如下面这个例子中: 

public   class  Hello 

    String s 
= "Hello"

    
public Hello(String s)
        System.out.println(
"s = " + s); 
        System.out.println(
"1 -> this.s = " + this.s); 
        
this.s = s; 
        System.out.println(
"2 -> this.s = " + this.s); 
    }
 

    
public static void main(String[] args) 
    Hello x
=new Hello("HelloWorld!"); 
    }
 
}
运行结果: 
=  HelloWorld !  
1   ->   this .s  =  Hello 
2   ->   this .s  =  HelloWorld !

        在这个例子中,构造函数Hello中,参数s与类Hello的变量s同名,这时如果直接对s进行操作则是对参数s进行操作。若要对类Hello的成员变量s进行操作就应该用this进行引用。运行结果的第一行就是直接对构造函数中传递过来的参数s进行打印结果;

                                                       第二行是对成员变量s的打印

                                                       第三行是先对成员变量s赋传过来的参数s值后再打印,所以结果是HelloWorld!

2. 把this作为参数传递 


当你要把自己作为参数传递给别的对象时,也可以用this如:

public   class  A 
  
public A() 
    
new B(this).print();   //  this就是类A,用new B(this)把对象A自己作为参数传递给了对象B的构造函数。
  }
 

  
public void print() 
    System.out.println(
"Hello from A!"); 
  }
 
}
 

public   class  B 
  A a; 
  
public B(A a) 
    
this.a = a; 
  }
 

  
public void print() 
    a.print(); 
    System.out.println(
"Hello from B!"); 
  }
 
}
 

运行结果: 
  Hello from A
!  
  Hello from B
!  

      在这个例子中,对象A的构造函数中,用new B(this)把对象A自己作为参数传递给了对象B的构造函数。


3. 注意匿名类和内部类中的中的this

      有时候,我们会用到一些内部类和匿名类,如事件处理。

           当在匿名类中用this时,这个this则指的是匿名类或内部类本身。

           这时如果我们要使用外部类的方法和变量的话,则应该加上外部类的类名。如下面这个例子:

public   class  A 
    
int i = 1

    
public A() 
        Thread thread 
= new Thread() 
            
public void run() 
                
for(;;) 
                    A.
this.run();  // 用外部类的类名加上 this 引用来说明要调用的是外部类的方法 run
                    
try 
                        sleep(
1000); 
                    }
 catch(InterruptedException ie) {     }

                }
 
           }
 
        }
//注意这里有; 
        thread.start(); 
    }
 

    
public void run() 
        System.out.println(
"i = " + i); 
        i
++
    }
 

    
public static void main(String[] args) throws Exception 
        
new A(); 
    }

}
 

          在上面这个例子中, thread 是一个匿名类对象,在它的定义中,它的 run 函数里用到了外部类的 run 函数。这时由于函数同名,直接调用就不行了。这时有两种办法,一种就是把外部的 run 函数换一个名字,但这种办法对于一个开发到中途的应用来说是不可取的。那么就可以用这个例子中的办法用外部类的类名加上 this 引用来说明要调用的是外部类的方法 run。

 

4。在构造函数中,通过this可以调用同一类中别的构造函数,如

public   class  Flower
           Flower (
int petals){} 
           Flower(String ss)
{} 
           Flower(
int petals, Sting ss)
                
//petals++;调用另一个构造函数的语句必须在最起始的位置 
                this(petals); 
               
//this(ss);会产生错误,因为在一个构造函数中只能调用一个构造函数 
           }
 
}
 


二、super() 方法的用法及作用?  


  1.   
  2. 有如下Java类:  
  3.   
  4.     public class Bird{   
  5.     private String name;   
  6.     public Bird() { }   
  7.     public Bird(String name){ this.name = name; }   
  8.     public void walk() { System.out.println(“走路”); }   
  9.     public String getName(){ return name; }   
  10.     public void setName(String name){ this.name = name; }   
  11.     }   
  12.   
  13. 另有一个类Chicken继承上边的Bird类;  
  14.   
  15.     public class Chicken extends Bird{   
  16.     private String crest;   
  17.     public Chicken(){ super(); }   
  18.     public Chicken(String name,String crest) {   
  19.     super(name);   
  20.     this.name = name; }   
  21.     ………….   
  22.     }   
  23.   
  24. 在第二个自定义的类Chicken中,super()方法一共出现了两次,分别是super()和super(name),请问super() 是什么含义,放在这里又作何解释?  
  25.   
  26. 参考答案:  
  27.   
  28. 1.子类的构造过程中必须调用父类的构造方法。  
  29.   
  30. 2.子类可在自己的构造方法中使用super()来调用父类的构造方法。  
  31.   
  32. 1)使用this来调用本类的另外的构造方法。  
  33.   
  34. 2)如果调用super必须写在子类构造方法的第一行。  
  35.   
  36. 3.如果子类的构造方法中没有显示的调用父类的构造方法,则系统默认的调用父类的无参的构造方法。  
  37.   
  38. 4.如果子类的构造方法中既没有显示调用父类的构造方法,而父类中又没有无参的构造方法,则编译出错。  
  39.   
  40. 那你这里第 一个super()无参的就是调用了上面Bird类的Bird() 无参构造方法!  
  41.   
  42.           super(name)这个有参数就是调用public Bird(String name){  this.name = name; }这个构造方法!

  43. super() 是调用父类的构造函数,你例子中有Bird()和Bird(String name)两个方法,super()是调用Bird()构造函数,而super(name)是调用Birth(String name)构造函数。注意super() 调用的是对应参数个数和类型相同的父类构造函数。 public Chicken(String name,String crest) { super(name); this.name = name; } 应该重复了吧,super(name)应该就是this.name = name。 

PS :

           1:在构造调用另一个构造函数,调用动作必须置于最起始的位置。

           2:不能在构造函数以外的任何函数内调用构造函数。

           3:在一个构造函数内只能调用一个构造函数。


(三)final关键字

1. final数据

    对于基本数据类型的数据而言,final修饰符表示,该数据不会被修改。
    对于非基本类型的对象引用而言,final修饰符所限定的引用恒定不变。一旦引用被初始化指向一个对象,就无法对其改变以指向另一个对象(然而,对象自身却是可以被修改的。Java并未提供任何使“对象”恒定不变的途径。这一限制同样适用于数组,它也是对象)。
                    

2. final方法---不能被重载

    使用final方法的原因有两个。第一个原因是把方法锁定,以预防任何继承类修改它的意义。这是出于设计的考虑:你想要确保在继承中方法的行为不变,并且不会被重写。
     注:类中的private方法隐含为final方法,它不可被重写。因此,在private方法前加上final修饰符是没有意义的。

3. final类--不能被继承,final类中的方法默认为final

    如果某个类整体被定义为final,则该类不可被继承,它不可有子类。这种设计可能是出于安全或其他方面的考虑。
    final类中的所有方法都隐含为final类型的,因为final类本身是不可被继承的,所以类中的方法也不能被重写(override)。在final类中,你可以给方法添加final修饰符,但这不会增加任何意义

    使用final方法的第二个原因是效率。如果你将一个方法指明为final,就是同意编译器将针对该方法的所有调用都转为内嵌(inline)调用。当编译器发现一个final方法调用命令时,它会根据自己的谨慎判断,跳过插入程序代码的正常方式而执行方法调用机制(将参数压入栈中,跳至方法代码处并执行,然后跳回去并清除栈中的参数,处理返回值),并且以方法体中的实际代码的复本来替代方法调用。这将消除方法调用的开销。当然,如果一个方法很大,你的程序代码就会膨胀,你可能看不到内嵌带来的任何性能提高。因此,你所取得的性能提高会因为花费于方法内时间总量而被缩减。这意味着Java编译器能够观察到这些情况并明智的抉择是否对final方法执行内嵌动作。然而,最好是让编译器和JVM仅在你明确表示要阻止重写(override)时,再考虑效率问题,并将方法指明为final。


     Java中除了static和final方法(private方法属于final)外,其他所有的方法都是后期绑定(动态绑定)。因此,将方法声明为final,可以有效的“关闭”动态绑定,或者是想告诉编译器,不需要对其进行动态绑定。这样,编译器就可以为final方法调用生成更有效的代码。然而,大多数情况下,这样做对程序的整体性能不会产生什么改观。


(四)static关键字(静态方法--静态变量--静态块--静态内部类)

     static表示“全局”或者“静态”的意思,用来修饰成员变量和成员方法,也可以形成静态static代码块,更可以修饰类级内部类,但是Java语言中没有全局变量的概念。 被static修饰的成员变量和成员方法独立于该类的任何对象。也就是说,它不依赖类特定的实例,被类的所有实例共享 。只要这个类被加载,Java虚拟机就能根据类名在运行时数据区的方法区内定找到他们 。因此,static对象可以在它的任何对象创建之前访问,无需引用任何对象。 

用public修饰的static成员变量和成员方法本质是全局变量和全局方法,当声明它类的对象时,不生成static变量的副本,而是类的所有实例共享同一个static变量。 static变量前可以有private修饰,表示这个变量可以在类的静态代码块中,或者类的其他静态成员方法中使用(当然也可以在非静态成员方法中使用--废话),但是不能在其他类中通过类名来直接引用,这一点很重要。实际上你需要搞明白,private是访问权限限定,static表示不要实例化就可以使用,这样就容易理解多了。static前面加上其它访问权限关键字的效果也以此类推。 

static修饰的成员变量和成员方法习惯上称为静态变量和静态方法,可以直接通过类名来访问,访问语法为: 

  • 类名.静态方法名(参数列表...) 
  • 类名.静态变量名 
用static修饰的代码块表示静态代码块,当Java虚拟机(JVM)加载类时,就会执行该代码块(用处非常大,呵呵)。 

1、static变量

按照是否静态的对类成员变量进行分类可分两种:一种是被static修饰的变量,叫静态变量或类变量;另一种是没有被static修饰的变量,叫实例变量。两者的区别是: 
  • 对于静态变量在内存中只有一个拷贝(节省内存),JVM只为静态分配一次内存,在加载类的过程中完成静态变量的内存分配,可用类名直接访问(方便),当然也可以通过对象来访问(但是这是不推荐的)。 
  • 对于实例变量,没创建一个实例,就会为实例变量分配一次内存,实例变量可以在内存中有多个拷贝,互不影响(灵活)。 

2、静态方法

静态方法可以直接通过类名调用,任何的实例也都可以调用,因此静态方法中不能用this和super关键字,不能直接访问所属类的实例变量和实例方法(就是不带static的成员变量和成员成员方法),只能访问所属类的静态成员变量和成员方法。因为实例成员与特定的对象关联!这个需要去理解,想明白其中的道理,不是记忆!!! 
因为static方法独立于任何实例,因此static方法必须被实现,而不能是抽象的abstract。 

3、static代码块

static代码块也叫静态代码块,是在类中独立于类成员的static语句块,可以有多个,位置可以随便放,它不在任何的方法体内,JVM加载类时会执行这些静态的代码块,如果static代码块有多个,JVM将按照它们在类中出现的先后顺序依次执行它们,每个代码块只会被执行一次。
    

4、类加载

   JVM在第一次使用一个类时,会到classpath所指定的路径里去找这个类所对应的字节码文件,并读进JVM保存起来,这个过程称之为类加载。

可见,无论是变量,方法,还是代码块,只要用static修饰,就是在类被加载时就已经"准备好了",也就是可以被使用或者已经被执行。都可以脱离对象而执行。反之,如果没有static,则必须通过对象来访问。

注意

   声明为static的变量实质上就是全局变量。当声明一个对象时,并不产生static变量的拷贝,而是该类所有的实例变量共用同一个static变量,例如:声明一个static的变量count作为new一个类实例的计数。

声明为static的方法有以下几条限制: 

  1. 它们仅能调用其他的static 方法。
  2. 它们只能访问static数据。
  3. 它们不能以任何方式引用this 或super。
  4. static方法与覆盖

      静态方法只能被隐藏,不能被覆盖,隐藏表明还存在,还会起作用--子类隐藏父类的静态方法,仍会执行父类的静态方法.

(五)synchronized


(六)中断线程的方法

   

Thread.stopThread.suspendThread.resume 和 Runtime.runFinalizersOnExit 这些终止线程运行的方法已经被废弃,使用它们是极端不安全的!
 
现在,如果你要安全有效地终止一个线程,应该采用以下这些方法:
 

1,线程正常执行完毕,正常结束。

也就是让run方法执行完毕,该线程就会正常结束。
 

2,监视某些条件,结束线程的不间断运行。

然而,常常有些线程是伺服线程。它们需要长时间的运行,只有在外部某些条件满足的情况下,才能关闭这些线程。
通常,它们执行在一个while(true)的死循环中。
如:
@Override
     public void  run() {
      
        while ( true ){
           someWork();
            if ( finished ){
               break ;
           }
            try  {
              Thread.sleep(10000);
           }  catch  (InterruptedException e) {
               /*  TODO 自动生成  catch 
               *
               */
              e.printStackTrace();
           }
       }
 
   }
我们可以在while死循环内,每次循环时,察看外部条件,看看是否需要关闭当前线程。如果是,就break,跳出死循环,或者是抛出异常,跳出死循环,结束线程。
 

3,捕获InterruptedException 运行时异常,中断当前线程。


 有些执行伺服任务的线程,在while(true)这样的死循环内部,是一个阻塞中的方法。此时,就不能采用第二种方法了。因为,当该方法没有返回时,该线程一直处于阻塞当中,根本无法执行其他语句。
如:
@Override
     public void  run() {
while ( true ){
            try  {
// getSendMessages  BlockingQueue 类。它的 take 方法将会阻塞!
              responseMessage =  this .getSendMessages().take();
           }  catch  (InterruptedException e1) {
   
               throw new  RuntimeException();
// 或者 break;
           }
             someWork();
      
    }
 
 
一个外部的Thread 对象 指向这个线程。 需要结束这个线程时,只需要调用thread对象的interrupt() 方法,就会在
responseMessage = this.getSendMessages().take();
这条语句中产生一个InterruptedException异常,从而结束该线程的阻塞状态,通过抛出异常,或者break跳出死循环,结束这个线程。
 




参考:http://www.cnblogs.com/lblxiaoyu/archive/2007/08/30/875603.html
       
         http://blog.csdn.net/a125138/article/details/7911942

         http://blog.csdn.net/shendl/article/details/1947453
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值