错题笔记(九)

面试很喜欢问的:
     首先,重载和重写都是多态的一种体现方式。重载是编译期间的活动,重写是运行期间的活动。
     其次,重载是在一个类中定义相同的名字的方法,方法的参数列表或者类型要互相不同,但是返回值类型不作为是否重载的标准,可以修改可见性;
     重写是不同的,要求子类重写基类的方法时要与父类方法具有相同的参数类型和返回值,可见性需要大于等于基类的方法

多态性 
通过继承,一个类可以用作多种类型:可以用作它自己的类型、任何基类型,或者在实现接口时用作任何接口类型。这称为多态性 

重载 : 相同名称成员的参数列表是不相同的(参数顺序和类型)。 重载的方法可看成一个全新的方法,与原方法相比它可以有不同的"可见度"和“返回值类型”。

重写 (重写 = 覆盖) 出现在父类与子类之间
派生的类型继承其基本类型的所有成员;也就是说,这些成员是在派生类型之上定义的,并可用于派生类型。继承成员的行为和质量可以通过以下两种方式来修改: 

1、派生类型可通过使用相同的签名定义一个新成员,从而隐藏继承的成员。将先前的公共成员变成私有成员,或者为标记为 final 的继承方法定义新行为时,可以采取这种方法。 

2、派生类型可以重写继承的虚方法。重写方法提供了对方法的一种新定义,将根据运行时的值的类型,而不是编译时已知的变量类型来调用方法。只有当虚方法没有标记为 final 且新方法至少可以像虚方法一样进行访问的情况下,成员才能重写虚方法。 
方法名,参数相同形成重写,重写的方法不能降低原方法的"可见度",也不能改变原方法的返回值类型。 

通俗的讲,就是基本数据类型和包装类之间的转换。如: int  类型和  Integer  类的转换
基本数据类型转化成包装类是装箱  (如: int  -->  Integer)。
包装类转化成基本数据类型就是拆箱  (如:Integer  -->  int)。
包装类就是引用类型,基本数据类型就是值类型。所以选C

final关键字

  1. final修饰符,可以修饰类,方法,变量,不能修饰接口
  2. final修饰的类不可以被继承
  3. final修饰的方法不可以被覆盖
  4. final修饰的变量为常量。只能赋值一次
  5. 一般final化的成员变量也会静态化

。用try-catch 捕获异常;
。用try-finally 清除异常;
。用try-catch-finally 处理所有的异常. 三者选一种即可

1.try块中放置可能引发异常的代码 故不可被省略

2.Jdk1.7中新增了多个catch块的功能,用以捕获多异常, 捕获顺序为先小后大

3.finally块用作回收无法被JVM回收的物理资源 例如数据库链接 网络链接等 Jdk1.7中虽增强了try()的功能,使得其中的代码在程序执行完毕后自动关闭代码 相当与隐含finally块

4.catch块用作捕获异常

总结

异常处理语法结构中只有try块是必须的,但不能只有try块,1.7中的增强try除外 因为其中的try()已经隐含了finally了 

可见性:

可见性是一种复杂的属性,因为可见性中的错误总是会违背我们的直觉。通常,我们无法确保执行读操作的线程能适时地看到其他线程写入的值,有时甚至是根本不可能的事情。为了确保多个线程之间对内存写入操作的可见性,必须使用同步机制。

可见性,是指线程之间的可见性,一个线程修改的状态对另一个线程是可见的。也就是一个线程修改的结果。另一个线程马上就能看到。比如:用volatile修饰的变量,就会具有可见性。volatile修饰的变量不允许线程内部缓存和重排序,即直接修改内存。所以对其他线程是可见的。但是这里需要注意一个问题,volatile只能让被他修饰内容具有可见性,但不能保证它具有原子性。比如 volatile int a = 0;之后有一个操作 a++;这个变量a具有可见性,但是a++ 依然是一个非原子操作,也就是这个操作同样存在线程安全问题。

在 Java 中 volatile、synchronized 和 final 实现可见性。

原子性:

原子是世界上的最小单位,具有不可分割性。比如 a=0;(a非long和double类型) 这个操作是不可分割的,那么我们说这个操作时原子操作。再比如:a++; 这个操作实际是a = a + 1;是可分割的,所以他不是一个原子操作。非原子操作都会存在线程安全问题,需要我们使用同步技术(sychronized)来让它变成一个原子操作。一个操作是原子操作,那么我们称它具有原子性。java的concurrent包下提供了一些原子类,我们可以通过阅读API来了解这些原子类的用法。比如:AtomicInteger、AtomicLong、AtomicReference等。

在 Java 中 synchronized 和在 lock、unlock 中操作保证原子性。

有序性:

Java 语言提供了 volatile 和 synchronized 两个关键字来保证线程之间操作的有序性,volatile 是因为其本身包含“禁止指令重排序”的语义,synchronized 是由“一个变量在同一个时刻只允许一条线程对其进行 lock 操作”这条规则获得的,此规则决定了持有同一个对象锁的两个同步块只能串行执行。

当一个变量定义为 volatile 之后,将具备两种特性:

1.保证此变量对所有的线程的可见性,这里的“可见性”,如本文开头所述,当一个线程修改了这个变量的值,volatile 保证了新值能立即同步到主内存,以及每次使用前立即从主内存刷新。但普通变量做不到这点,普通变量的值在线程间传递均需要通过主内存(详见:Java内存模型)来完成。

2.禁止指令重排序优化。有volatile修饰的变量,赋值后多执行了一个“load addl $0x0, (%esp)”操作,这个操作相当于一个内存屏障(指令重排序时不能把后面的指令重排序到内存屏障之前的位置),只有一个CPU访问内存时,并不需要内存屏障;(什么是指令重排序:是指CPU采用了允许将多条指令不按程序规定的顺序分开发送给各相应电路单元处理)。

volatile 性能:

volatile 的读性能消耗与普通变量几乎相同,但是写操作稍慢,因为它需要在本地代码中插入许多内存屏障指令来保证处理器不发生乱序执行。

摘自Java中Volatile关键字详解 - 郑斌blog - 博客园

上一篇:【C# 线程】 volatile 关键字


下一篇:java多线程基础