《Thinking in Java》学习笔记(二)

时间:2021-10-17 05:56:39

1.Java方法的重载

  如果几个方法都有相同的名字,区分它们就需要重载来完成。

  构成重载的种类:

  1)形参的个数不同  2) 形参的类型不同 3) 形参的顺序不同

  

  注意,返回值、抛出的异常和修饰符的不同是不能作为重载的依据的。

2.super和this

  什么情况下需要用到this:
       
  第一、通过this调用另一个构造方法,用法是this(参数列表),这个仅仅在类的构造方法中,别的地方不能这么用。
       
  第二、函数参数或者函数中的局部变量和成员变量同名的情况下,成员变量被屏蔽,此时要访问成员变量则需要用“this.成员变量名”的方式来引用成员变量。当然,在没有同名的情况下,可以直接用成员变量的名字,而不用this,用了也不为错。
       
  第三、在函数中,需要引用该函所属类的当前对象时候,直接用this。

  什么情况下需要用到super:
       
  第一、在子类构造方法中要调用父类的构造方法,用“super(参数列表)”的方式调用,参数不是必须的。同时还要注意的一点是:“super(参数列表)”这条语句只能用在子类构造方法体中的第一行。
       
  第二、当子类方法中的局部变量或者子类的成员变量与父类成员变量同名时,也就是子类局部变量覆盖父类成员变量时,用“super.成员变量名”来引用父类成员变量。当然,如果父类的成员变量没有被覆盖,也可以用“super.成员变量名”来引用父类成员变量,不过这是    不必要的。
       
  第三、当子类的成员方法覆盖(重写)了父类的成员方法时,也就是子类和父类有完全相同的方法定义(但方法体可以不同),此时,用“super.方法名(参数列表)”的方式访问父类的方法。

3.finalize关键字

  JVM保证在一个对象所占用的内存被回收之前,如果它实现了finalize方法,则该方法一定会被调用。Object的默认finalize什么都不做,为了效率,GC可以认为一个什么都不做的finalize不存在。

  用Java以外的代码编写的Class(比如JNI,C++的new方法分配的内存),垃圾回收器并不能对这些部分进行正确的回收,这时就需要我们覆盖默认的方法来实现对这部分内存的正确释放和回收(比如C++需要delete)。

  如果不是调用了非Java的代码,finalize就不应过多的使用。

  子类一旦复写了finalize(),必须调用super.finalize(),否则父类的finalize()不执行。

  JVM的gc有minor GC和major GC(也就是大家说的Full GC),JVM会很频繁的做minor GC,如果内存块占满的话,JVM会做Full GC,Full GC是对整个JVM内存堆做GC,所示耗时比minor GC要长很多。

  调用System.gc()也仅仅是一个向JVM的GC请求(建议),但是进行的是Full GC,所以System.gc()还是要少显示地调用。

4.运行时绑定(动态绑定)

  子类重写父类中的方法,就会调用子类中的方法。

  子类没有重写父类中的方法,就会调用父类中相应的方法。

  动态绑定只是针对对象的方法,对于属性无效。

  private、static、final的方法是无法动态绑定的。

调用子类的构造函数时会默认地调用父类无参的构造方法,若需要调用父类其他的构造方法,则需要显示地调用。

5.可变长参数

  在调用方法的时候,如果能够和固定参数的方法匹配,也能够与可变长参数的方法匹配,则会调用固定参数的方法。

  一个方法只能有一个可变长参数,并且这个可变长参数必须是该方法的最后一个参数,如:
    public void print(int input,String...args ){...}是正确的,
    而public void test(String... strings,int input){...}是不正确的。

6.Java方法的覆盖

(1)重写方法不能缩小访问权限;

(2)参数列表必须与被重写方法相同(包括显示形式);

(3)返回类型必须与被重写方法的相同或是其子类;

(4)重写方法不能抛出新的异常,或者超过了父类范围的异常,但是可以抛出更少、更有限的异常,或者不抛出异常。

  

  覆盖只是针对方法的,变量是不能覆盖的。子类覆盖了父类的方法,在调用子类方法时就会运行时绑定,上面的第4条有说明。

package override;

public class People {
protected String name="people";

 public String say(){
    return "people method";
   }
}
package override;

public class Student extends People {
protected String name="student";
 @Override
  public String say(){
    return "student method";
  } public static void main(String[] args) {
People p=new People();
System.out.println(p.name);//运行结果为people
Student s=new Student();
System.out.println(s.name);//运行结果为student
People pp=new Student();
System.out.println(pp.name);//运行结果为people

  System.out.println(pp.say()); //运行结果为student method
}
}

7.单例模式可以被继承吗?

  子类的构造函数默认地会调用父类无参的构造函数。

  饿汉式单例和懒汉式单例由于构造方法是private的,所以他们都是不可继承的,但是其他很多单例模式是可以继承的,例如登记式单例。

  构造函数:1、方法名与类相同 2、不能有返回值 3、不能用static、final、sychronized、abstract和native修饰。

  如果使用package语句,则该语句一定是除了注释之外的第一行代码。

  虽然不是很常用,但是编译单元中可以没有public类型的类,这时文件是可以随意命名的。正常情况下只能存在一个public的类,且文件和该类同名。

  如果父类只有一个有参数的构造函数,则子类构造函数的第一句只能是显示地调用父类的构造函数。

8.final关键字

  使用final的三种情况:变量,方法和类

  1>final变量

  final变量在使用前必须被初始化。2个地方可以完成初始化动作:一是定义时,二是在每个构造方法中完成。

  基本类型的final值是不能被改变的,对象的final是指引用是不能改变的,引用的属性还是可以改变的。

  final Person p = new Person();

  p = new Person() ; // error

  p.setName("new name"); //ok

  p.setName("another name"); //ok

  既是final又是static的值被称为常量,常量用大写字母表示,用下划线分割每个单词,例如:

2>final方法

  早期的Java版本中final方法用于提高运行效率,但是JDK5之后,已经不再需要使用final方法来进行效率的优化了。

  final用于方法的唯一的原因就是不希望方法被子类所覆盖。

  private方法隐式地指定为final型,给private方法加上final修饰词是无意义的。

  3>final类

  处于某种考虑,类的设计不需要做出任何变动,或者出于安全的考虑,不希望类有子类,这时可以将类定义为final的。