Java超简明入门学习笔记(三)

Java编程思想第4版学习笔记(三)

第五章 初始化与清理(构造器和垃圾回收机制)

 

Java有和C++类似的构造函数来为新创建的对象执行初始化及完成一些特殊的操作,有的类数据成员可能会被初始化几次,它们的初始化次序和次数是根据程序决定的,可以用重载的构造函数以不同的形式对一个对象初始化,重载的构造函数之间可以通过this互相调用。最后,本章讲了finalize()函数和简单的GC机制,也提到了如何创建一个数组。

 

知识点1:P76,5.1,定义构造函数

当对象被创建时,构造函数会自动被调用,构造器的函数名和类名相同,无返回值类型(也不是void类型,就是不需要任何类型),可以有任意个参数,在函数体里写上你想让该类对象被创建时会发生的事情。创建对象时要给对象符合构造器(构造函数的另一种说法)要求的参数。不需要任何参数的构造器被称为“无参构造器”或“默认构造器”。

如果你写的类没有任何构造函数,Java会自动帮你创建出一个无参构造器,它做的事只是把类内成员初始化为0或那个类型默认的初始值。如果你写了一个或多个构造器(无论带不带参数),系统将不再自动生成一个无参构造器。

一个含有显式构造器的类的实例被初始化的顺序是这样的:

在构造函数被调用之前,静态变量首先被初始化为默认值或类内初始值(这一行为被这本书称为指定初始化,具体做法是在类字段定义时就用字段=对象;的方式初始化字段),然后一般变量首先被初始化为默认值或类内初始值。之后,会执行接下来会提到的“初始化子句”,最后,构造函数如果有初始化类数据成员的语句,则,这些语句依次对数据成员初始化。另外,静态类数据成员只要被访问,哪怕没有实例存在,也会完成初始化。

知识点2:P77,5.2,方法重载

同一个类里可以有多个同名函数,这些函数的参数类型或参数数量不一样使使用者可以通过不同的参数组合调用一个名字的参数,这种形式叫方法重载。定义一个重载的函数,只需要通过正常的定义函数的形式,把函数名设定为想要重载的函数名,把参数列表变成不一样的就行了。

重载之后,如果传入的实参类型并非任意一个重载函数需要的类型,但经过非窄化转换仍能匹配所有的重载函数需要的参数类型,这个参数就会类型提升为更接近它的那一个函数需要的参数类型,参与运算。

 

知识点3:P84,5.4,this

this可以出现在非静态函数体内,代表当前函数所属对象的一个引用。在一个构造器中调用另一个构造器,必须使用this(构造器参数);的形式,一个构造器中只能通过这种方法调用一次别的构造器,且这个调用要放在函数最开始。

知识点4:P87,5.5,垃圾回收与finalize()函数

垃圾回收器要回收对象的时候,首先要调用这个类的finalize方法),一般的纯Java编写的Class不需要重新覆盖这个方法,因为Object已经实现了一个默认的,除非我们要实现特殊的功能。如果想覆盖Object的finalize方法,只需声明一个 protected void finalize( ) { } 这样的函数。在函数里写一些你想要Java的GC回收对象之前你想做的事情。

Java中有一个有趣的函数,叫System.gc();,这个函数的作用是提醒JVM:程序员觉得应该进行一次垃圾回收了。至于到底JVM真的开始了垃圾回收,还是没有理你的这个意愿,认为根本没必要浪费时间和资源进行垃圾回收,那就是JVM自己的事情了。

Java垃圾回收的机理在于遍历对象和对象的引用,只要发现某个对象不可达,即在代码执行的某一过程中无法通过任何引用(或者这个对象目前根本就没有引用)访问这个对象,这个对象就失去的存在的意义,会被回收。不过具体的回收时机,不同的JVM实现上也不尽相同。

知识点5:P87,5.7.3,静态初始化子句和实例初始化子句

如果你需要在构造函数里额外执行一些语句,又实在懒得写构造函数,你可以使用如下所示的方法(静态/实例初始化子句)实现这个目的。红色的部分就是初始化子句。初始化子句会在默认初始化和构造器初始化之间被调用。

class staticClass{

static int i = 0;

static{

i = 9;

System.out.println("i = 9");

}
}

class sampleClass{

int i =0;

{

i = 89;

System.out.println("i = 89");

}

}

知识点6:P98,5.8,数组

数组是一种能够容纳多个元素的重要结构。要定义一个某种类型的数组,只需这样做:类型名[] 数组名; 或者 类型名 数组名[]; ,比如 int[] a1;  和一些语言不同,不能够用类似C/C++那样的方式指定数组的大小,只能创建一个数组的引用(即数组名)来操控它代表的真正数组对象。使用一个空(值为null)的数组引用也将出现错误,因此要在这个数组引用初始化之后再使用。可以使用初始化表达式,即一对大括号包围起来的一个元素的列表来初始化数组,比如int[] a = { 1,2,3,4 };,这种初始化方法只能够用于数组定义之处。也可以把另一个数组的引用所指代的对象传递给这个引用,比如int[] a2 = a;。最后,还可以通过new关键字创建数组对象和其引用,比如int[] c = new int[30]; 或者 int[] a = new int[]{1,2,3,4}; 来初始化。

正如上一章所说,数组可被用于foreach循环。

数组对象有一个叫做toString的方法,这个方法不需要参数,可以把数组转换成合适的字符串。也可以使用Array.toString(数组名)的静态方法达到同样的目的。

知识点7:P102,5.8.1,可变参数列表

我们有时候可能需要这么一种函数,这个函数需要传入一些参数,这些参数类型是固定的,但我们并不知道会传入几个这个类型的参数。这时我们就需要这个特性。我们可以在参数列表里放一个数组来解决这个问题。

比如 void func(int 1, char[] c); 我们想要使用这个函数,就可以这么调用它:func(1, new char[]{‘a‘,‘b‘,‘c‘}); 不过这种写法需要显式创建一个数组对象并且传入,我们可以用这种写法代替原来的函数定义void func(int i, char... c){}; ,这种定义方式可以允许我们这么调用它:func(1,‘a‘,‘b‘,‘c‘); ,大大简略了语法。Java的函数重载时,即使实参可以转化为多种函数需要的形参类型,不过Java有粒度很细的优先转换的规则,可以使这个调用总能匹配到一个“最容易转化”的,因此不会产生二义性调用(C++函数匹配则只有5个等级,每个等级间的各个调用形式是优先度一致的,因此可能产生二义性调用)。

可变参数列表必须放在参数列表的最后且每个函数只能有一个可变形参。

知识点8:P105,5.9,枚举类型

和其他主流语言一样,Java也提供了枚举类型,它的关键字是enum,用来方便的定义枚举类型,定义枚举类型的方式类似与定义一个类:enum testSize{ SMALL, MIDIUM, LARGE }; ,使用时,可以为testSize枚举类型创建一个实例:testSize s = testSize.SMALL; 枚举类型的对象有toString,ordinal等方法,ordinal()返回一个从0开始的当前枚举值在枚举类型中被定义时的次序。此外,枚举类型还提供values()静态函数,返回所有枚举情况的集合,使编程者可以遍历每个枚举值。

     第五章 练习题

     练习1、2:创建一个类,它包含一个未初始化的String域,一个在定义时就初始化的String域,一个构造器初始化的String域。验证第一个String域被默认初始化为了null,探究第二和第三个String域的差异。

 1 class StringTest{
 2     StringTest(){
 3         s3 = "4567";
 4     }
 5
 6     String s1;
 7     String s2 = "1234";
 8     String s3;
 9 }
10
11 public class MainTest {
12     public static void main(String[] args) {
13         StringTest st = new StringTest();
14         System.out.println(st.s1);
15         System.out.println(st.s2);
16         System.out.println(st.s3);
17     }
18 }

练习1、2答案

     练习3、4:创建一个带无参构造器的类,在构造器中打印一条信息,为这个类创建一个对象。在为这个类创建一个重载构造器,这个构造器需要一个字符串做参数,并把接收的字符串也打印出来。

 1 class Test{
 2     Test(){
 3         System.out.println("Test");
 4     }
 5
 6     Test(String s){
 7         System.out.println(s+"test");
 8     }
 9 }
10
11 public class MainTest {
12     public static void main(String[] args) {
13         Test t = new Test();
14         Test t2 = new Test("1234");
15     }
16 }

练习3、4答案

     练习5、6:创建一个名为Dog的类,它具有重载的bark()方法,此方法根据不同的基本数据类型进行重载,并根据被调用的版本,打印出不同类型的barking,howling等信息。编写对应的主函数调用所有不同版本的方法。再试着写两个构造函数,它们都需要两个不同类型的参数,但是这两个构造函数需要的参数类型顺序正好相反,试试调用它们。

 1 class Dog{
 2     Dog(int i){
 3         System.out.println("barking");
 4     }
 5
 6     Dog(double d){
 7         System.out.println("howling");
 8     }
 9
10     Dog(char c){
11         System.out.println("Meow~");
12     }
13
14     Dog(int i, boolean b){
15         System.out.println("I B");
16     }
17
18     Dog(boolean b, int i){
19         System.out.println("B I");
20     }
21 }
22
23 public class MainTest {
24     public static void main(String[] args) {
25         Dog d1 = new Dog(1);
26         Dog d2 = new Dog(1.5);
27         Dog d3 = new Dog(‘c‘);
28
29         Dog bi1 = new Dog(1,true);
30         Dog bi2 = new Dog(true,1);
31     }
32 }

练习5、6答案

     练习7:创建一个没有构造器的类,并在main()中创建其对象,用以验证编译器是否真的自动加入了默认构造器。

 1 class Test{
 2     int i;
 3     double d;
 4 }
 5
 6 public class MainTest {
 7     public static void main(String[] args) {
 8         Test t = new Test();
 9         System.out.println(t.i);
10         System.out.println(t.d);
11     }
12 }

练习7答案

     练习8:编写具有两个方法的类,在第一个方法内调用第二个方法两次:第一次调用时不使用this关键字,第二次调用使用关键字,来验证this关键字的作用。

 1 class Test{
 2     void method1(){
 3         method2();
 4         this.method2();
 5     }
 6
 7     void method2(){ System.out.println("Ah,be called!!"); }
 8 }
 9
10 public class MainTest {
11     public static void main(String[] args) {
12         Test t = new Test();
13         t.method1();
14     }
15 }

练习8答案

     练习9:编写具有两个(重载)构造器的类,并在第一个构造器中通过this调用第二个构造器。

 1 class Test{
 2     Test(String s, double i){
 3         this(i);
 4         ss = s;
 5
 6         System.out.println("name: "+ss);
 7         System.out.println("Area: "+ii);
 8     }
 9
10     Test(double i){
11         ii = i*i*3.14;
12     }
13
14     String ss;
15     double ii;
16 }
17
18 public class MainTest {
19     public static void main(String[] args) {
20         Test t = new Test("Circle",2);
21     }
22 }

练习9答案

     练习10、11:编写具有finalize()方法的类,并在方法中打印消息,在main()中为该类创建一个对象,研究finalize和System.gc()和finalize()的联系。

 1 class Test{
 2     protected void finalize(){
 3         //super.finalize();
 4         System.out.println("Ah!!NO!!!");
 5     }
 6 }
 7
 8 public class MainTest {
 9     public static void main(String[] args) {
10         Test t = new Test();
11         System.gc();
12     }
13 }

练习10、11答案

     练习12:编写名为Tank的类,此类的状态可以是“满的”或者“空的”,其终结条件是:对象是空的,编写finalize()函数以在gc之前检验对象状态。

 1 class Tank{
 2     protected void finalize(){
 3         //super.finalize();
 4         if(isFull){
 5             System.out.println("Not Good");
 6         }
 7         else{
 8             System.out.println("Good!");
 9         }
10     }
11
12     boolean isFull = false;
13 }
14
15 public class MainTest {
16     public static void main(String[] args) {
17         Tank t = new Tank();
18         System.gc();
19     }
20 }

练习12答案

     练习13:调试书上代码,略。

     练习14:编写一个类,拥有两个静态字符串域,其中一个在定义处初始化,另一个在静态块中初始化。现在加入一个静态方法打印这两个字段的值,查看它们是否都会在被使用之前完成初始化动作。

 1 class Test{
 2     static String s1 = "1234";
 3     static String s2;
 4     static{
 5         s2 = "4567";
 6     }
 7
 8     static void func(){
 9         System.out.println(Test.s1);
10         System.out.println(Test.s2);
11     }
12 }
13
14 public class MainTest {
15     public static void main(String[] args) {
16         Test.func();
17     }
18 }

练习14答案

     练习15:编写一个含有字符串域的类,并采用实例初始化方式进行初始化。

1 class Test{
2     String s1;
3     {
4         s1 = new String("1234");
5     }
6 }

练习15答案

     练习16:创建一个String对象数组,并为每一个元素都赋值一个String,用for循环来打印此数组。

1 public class MainTest {
2     public static void main(String[] args) {
3         String[] arrayString = {"1111","2222","3333","4444"};
4         for(String s:arrayString)
5         {
6             System.out.println(s);
7         }
8     }
9 }

练习16答案

     练习17、18:创建一个类,它有一个构造器,这个构造器接收一个String类型的参数。在构造阶段,打印此参数。创建一个该类对象的引用数组,但是不实际地创建对象赋值给该数组。试着运行程序。再试着通过创建对象,再赋值给引用数组,从而完成程序。

 1 class Test{
 2     Test(String s){
 3         System.out.println(s);
 4     }
 5 }
 6
 7 public class MainTest {
 8     public static void main(String[] args) {
 9         Test[] arrayTest = new Test[]{
10                 new Test("123"),
11                 new Test("456")
12         };
13     }
14 }

练习17、18答案

     练习19:创建一个类,它的构造函数接受一个可变参数的String数组。验证你可以向该方法传递一个用逗号分隔的String实参列表,或是一个String[]。

 1 class Test{
 2     Test(String... s){
 3     }
 4 }
 5
 6 public class MainTest {
 7     public static void main(String[] args) {
 8         Test t1 = new Test("111","222");
 9         Test t2 = new Test(new String[]{"333","444"});
10     }
11 }

练习19答案

     练习20:创建一个使用可变参数列表而不是用普通main()语法的主函数main(),打印args数组的传入的命令行参数。

1 public class MainTest {
2     public static void main(String... args) {
3         for(String s:args)
4         {
5             System.out.println(s);
6         }
7     }
8 }

练习20答案

     练习21、22:创建一个enum,它包含纸币中最小面值的6种类型,通过values()循环并打印每一个值以及其ordinal()。最后再试着使用带enum类型的switch语句。

 1 enum CNY{
 2     CNY1,CNY5,CNY10,CNY20,CNY50,CNY100;
 3 }
 4
 5 public class MainTest {
 6     public static void main(String[] args) {
 7         for (CNY temp : CNY.values()) {
 8             System.out.println(temp + " " + temp.ordinal());
 9         }
10
11         CNY cnyTemp = CNY.CNY5;
12         switch (cnyTemp){
13             case CNY1:
14                 System.out.println("1 Yuan");
15                 break;
16
17             case CNY5:
18                 System.out.println("5 Yuan");
19                 break;
20
21             case CNY10:
22                 System.out.println("10 Yuan");
23                 break;
24
25             case CNY20:
26                 System.out.println("20 Yuan");
27                 break;
28
29             case CNY50:
30                 System.out.println("50 Yuan");
31                 break;
32
33             case CNY100:
34                 System.out.println("100 Yuan");
35                 break;
36
37             default:
38                 System.out.println("Error : Fake Money");
39         }
40     }
41 }

练习21、22答案

body,td { font-family: 微软雅黑; font-size: 10pt }

时间: 2024-07-29 14:07:19

Java超简明入门学习笔记(三)的相关文章

Java超简明入门学习笔记(零)

Java编程思想第4版学习笔记(零) 前言   这个笔记本主要记录了我在学习Java编程思想(第4版,中文版)的过程中遇到的重难点及其分析.主要参考了C++11版本的C++语言,对比了它们不同的部分. <Java编程思想(第四版)>早在2007年就已经出版了,时值Java SE5~Java SE6升级的时间节点,现在10年过去了,Java语法标准已经到了Java 8,Java 9也快出来了,不过这本书仍然充满对Java探索的智慧,书上所讲的语法也绝大多数没有失效 ,是很方便读者全面系统了解Ja

Java超简明入门学习笔记(二)

Java编程思想第4版学习笔记(二) 第三章 操作符 & 第四章 控制执行流程(流程控制语句)   第三章和第四章的内容主要是讲操作符和流程控制语句,Java的大多数操作符和流程控制语句都和C/C++的十分类似,因此把这两章内容汇成一章,挑出Java独特的地方进行学习.         第三章   知识点1:P39,3.2,操作符,优先级 Java操作符和其他语言一样,作用于操作数,产生新值.各个操作符的优先级和结合性类似C/C++. 这里有一些特殊的地方: + 操作符可以用于字符串,把字符串和

Java多线程高并发学习笔记(三)——深入理解线程池

线程池最核心的一个类:ThreadPoolExecutor. 看一下该类的构造器: public ThreadPoolExecutor(int paramInt1, int paramInt2, long paramLong, TimeUnit paramTimeUnit, BlockingQueue<Runnable> paramBlockingQueue) { this(paramInt1, paramInt2, paramLong, paramTimeUnit, paramBlockin

汇编入门学习笔记 (三) —— 第一个程序

疯狂的暑假学习之  汇编入门学习笔记 (三)-- 第一个程序 参考:<汇编语言> 王爽  第四章 1.一个源程序从写到执行的过程 第一步:编写汇编源程序 第二步:对源程序进行编译连接 第三步:在操作系统中执行 2.源程序 代码: assume cs:first first segment start: mov ax,2 add ax,ax add ax,ax mov ax,4C00H int 21H first ends end start 代码解释: assume .segment.ends

Hadoop入门学习笔记---part1

随着毕业设计的进行,大学四年正式进入尾声.任你玩四年的大学的最后一次作业最后在激烈的选题中尘埃落定.无论选择了怎样的选题,无论最后的结果是怎样的,对于大学里面的这最后一份作业,也希望自己能够尽心尽力,好好做.正是因为选题和hadoop有关,现在正式开始学习hadoop.将笔记整理于此,希望与志同道合的朋友共同交流. 作者:itRed 邮箱:[email protected] 个人博客链接:http://www.cnblogs.com/itred 好了,废话不多说.进入正题!开始hadoop的学习

Ajax学习笔记(三)

三.jQuery库详解 1.使用jQuery之后,javascript操作的不再是HTML元素对应的DOM对象,而是包装DOM对象的jQuery对象.js通过调用jQuery对象的方法来改变它所包装的DOM对象的属性,从而实现动态更新HTML页面. 由此可见,使用jQuery动态更新HTML页面只需以下两个步骤: (1)获取jQuery对象.jQuery对象通常是DOM对象的包装 (2)调用jQuery对象的方法来改变自身.当jQuery对象被改变时,jQuery包装的DOM对象随之改变,HTM

JNI入门-学习笔记

JNI入门-学习笔记 可执行文件 Windows - *.exe | linux - *.elf c函数库文件 Windows - *.dll | linux - *.so 批处理文件 Windows - *.bat | linux - *.sh 工具 NDK -- native developer kits Cygwin -- Linux系统模拟器 安装过程要点: ——安装时可以联网安装也可以通过本地文件安装(如果有本地文件) ——Select Packages:没必要全部安装,安装Devel

android JNI入门-学习笔记

JNI入门-学习笔记 可执行文件 Windows - *.exe | linux - *.elf c函数库文件 Windows - *.dll | linux - *.so 批处理文件 Windows - *.bat | linux - *.sh 工具 NDK -- native developer kits Cygwin -- Linux系统模拟器 安装过程要点: --安装时可以联网安装也可以通过本地文件安装(如果有本地文件) --Select Packages:没必要全部安装,安装Devel

Hadoop入门学习笔记---part4

紧接着<Hadoop入门学习笔记---part3>中的继续了解如何用java在程序中操作HDFS. 众所周知,对文件的操作无非是创建,查看,下载,删除.下面我们就开始应用java程序进行操作,前提是按照<Hadoop入门学习笔记---part2>中的已经在虚拟机中搭建好了Hadoop伪分布环境:并且确定现在linux操作系统中hadoop的几个进程已经完全启动了. 好了,废话不多说!实际的例子走起. 在myeclipse中新建一个java工程: 在项目工程中新建一个lib包用于存放