你的位置:首页 > Java教程

[Java教程]java 编程思想 第五章 初始化与清理


1.重载(overloading)和重写(overriding)

  重载(overloading)

  (1)方法重载是让类以统一的方式处理不同类型数据的一种手段。多个同名函数同时存在,具有不同的参数个数/类型。重载Overloading是一个类中多态性的一种表现。

      (2) Java的方法重载,就是在类中可以创建多个方法,它们具有相同的名字,但具有不同的参数和不同的定义。调用方法时通过传递给它们的不同参数个数和参数类型来决定具体使用哪个方法, 这就是多态性(静态多态性)。

      (3) 重载的时候,方法名要一样,但是参数类型和个数不一样,返回值类型可以相同也可以不相同。无法以返回型别作为重载函数的区分标准。

  重写(overriding)

      (1)父类与子类之间的多态性,对父类的函数进行重新定义。如果在子类中定义某方法与其父类有相同的名称和参数,我们说该方法被重写 (Overriding)。在Java中,子类可继承父类中的方法,而不需要重新编写相同的方法。但有时子类并不想原封不动地继承父类的方法,而是想作一定的修改,这就需要采用方法的重写。方法重写又称方法覆盖。


      (2)若子类中的方法与父类中的某一方法具有相同的方法名、返回类型和参数表,则新方法将覆盖原有的方法。如需父类中原有的方法,可使用super关键字,该关键 字引用了当前类的父类。


      (3)子类函数的访问修饰权限不能少于父类的;

  根据方法的返回值区分重载方法是行不通的

  类如果已经有了一个构造器(无论是否有参数),编译器就不会帮你自动创建默认构造器

  this关键字只能在方法内部使用,表示对‘调用方法的对象’的引用

  尽管可以用this调用一个构造器,但却不能调用两个,必须将构造器调用置于最起始出,否则编译器会报错。除构造器之外,编译器禁止在其他任何方法中调用构造器。

static关键字

  在static方法内部不能调用非静态方法,反过来是可以的。

  方便在没有创建对象的情况下来进行调用(方法/变量)。

  很显然,被static关键字修饰的方法或者变量不需要依赖于对象来进行访问,只要类被加载了,就可以通过类名去进行访问。

  static方法一般称作静态方法,由于静态方法不依赖于任何对象就可以进行访问,因此对于静态方法来说,是没有this的,因为它不依附于任何对象,既然都没有对象,就谈不上this了。

  另外记住,即使没有显示地声明为static,类的构造器实际上也是静态方法。

 

  static变量也称作静态变量,静态变量和非静态变量的区别是:静态变量被所有的对象所共享,在内存中只有一个副本,它当且仅当在类初次加载时会被初始化。而非静态变量是对象所拥有的,在创建对象的时候被初始化,存在多个副本,各个对象拥有的副本互不影响。

  static成员变量的初始化顺序按照定义的顺序进行初始化。

 

     static块可以置于类中的任何地方,类中可以有多个static块。在类初次被加载的时候,会按照static块的顺序来执行每个static块,并且只会执行一次。

  为什么说static块可以用来优化程序性能,是因为它的特性:只会在类加载的时候执行一次。

 

  static是不允许用来修饰局部变量。不要问为什么,这是Java语法的规定。

常见面试题

 1.下面这段代码的输出结果是什么?

public class Test extends Base{     static{        System.out.println("test static");    }         public Test(){        System.out.println("test constructor");    }         public static void main(String[] args) {        new Test();    }} class Base{         static{        System.out.println("base static");    }         public Base(){        System.out.println("base constructor");    }}

 

base statictest staticbase constructortest constructor

  至于为什么是这个结果,我们先不讨论,先来想一下这段代码具体的执行过程,在执行开始,先要寻找到main方法,因为main方法是程序的入口,但是在执行main方法之前,必须先加载Test类,而在加载Test类的时候发现Test类继承自Base类,因此会转去先加载Base类,在加载Base类的时候,发现有static块,便执行了static块。在Base类加载完成之后,便继续加载Test类,然后发现Test类中也有static块,便执行static块。在加载完所需的类之后,便开始执行main方法。在main方法中执行new Test()的时候会先调用父类的构造器,然后再调用自身的构造器。因此,便出现了上面的输出结果。

 

  1.下面这段代码的输出结果是什么?

 1 public class Test { 2     Person person = new Person("Test"); 3     static{ 4         System.out.println("test static"); 5     } 6       7     public Test() { 8         System.out.println("test constructor"); 9     }10      11     public static void main(String[] args) {12         new MyClass();13     }14 }15  16 class Person{17     static{18         System.out.println("person static");19     }20     public Person(String str) {21         System.out.println("person "+str);22     }23 }24  25  26 class MyClass extends Test {27     Person person = new Person("MyClass");28     static{29         System.out.println("myclass static");30     }31      32     public MyClass() {33         System.out.println("myclass constructor");34     }35 }

test staticmyclass staticperson staticperson Testtest constructorperson MyClassmyclass constructor

  类似地,我们还是来想一下这段代码的具体执行过程。首先加载Test类,因此会执行Test类中的static块。接着执行new MyClass(),而MyClass类还没有被加载,因此需要加载MyClass类。在加载MyClass类的时候,发现MyClass类继承自Test类,但是由于Test类已经被加载了,所以只需要加载MyClass类,那么就会执行MyClass类的中的static块。在加载完之后,就通过构造器来生成对象。而在生成对象的时候,必须先初始化父类的成员变量,因此会执行Test中的Person person = new Person(),而Person类还没有被加载过,因此会先加载Person类并执行Person类中的static块,接着执行父类的构造器,完成了父类的初始化,然后就来初始化自身了,因此会接着执行MyClass中的Person person = new Person(),最后执行MyClass的构造器。

  

垃圾回收机制  

  由于垃圾回收器只知道释放那些经由new分配的内存,所以它不知道如何释放该对象的这块“特殊”内存(使用本地方法的情况)。为了应对这种情况,java允许在类中定义一个名为finalize()的方法。一旦垃圾回收器准备好释放该对象占用的存储空间,将首先调用其finalize()方法,并且在下一次垃圾回收动作发生时,才会真正回收对象占用的空间。 

  当垃圾回收器工作时,将一面回收空间,一面将堆中的对象紧凑排列。

  引用记数是一种简单但速度很慢的垃圾回收技术,这种方法有个缺点,如果对象之间存在循环引用,可能会出现“对象应该被回收,当引用不为零”的情况,未被应用于任何一种java虚拟机。

  标记-清扫  所依据的思路是从堆栈和静态存储区出发,遍历所有的引用,进而找到所有存活的对象。没找到一个存活对象,就会给对象设一个标记,这个过程不会回收任何对象。只有标记工作完成后,清理工作才会开始。

初始化

  无法阻止自动初始化的进行,它将在构造器调用之前发生。

  在类的内部,变量定义的先后顺序决定了初始化的顺序。

  无论创建多少个对象,静态数据都只占用一份存储区域。static关键字不能应用于局部变量。

  数字初始化

        int a2[];		int[] a1 = {1,2,3,4,5};		a2 = a1;		for(int i = 0; i< a2.length; i++){			a2[i] = a2[i] + 1;		}				int[] b;		Random rand = new Random(47);		b = new int[rand.nextInt(20)];		System.out.print(Arrays.toString(b));        

  枚举类型

enum Spiciness{  NOT,MILD,MEDIUM,HOT,FLAMING}for(Spiciness s : Spiciness.values()){      System.out.println(s +"" + s.ordinal());    }    Spiciness degree;switch (degree) {  case NOT:          break;  case MILD:          break;  default:  break;}