java编程思想第四版第五章总结
1. 构造器
- 构造器的一个重要的作用: 保证对象被使用之前初始化了.
- 构造器是一种特殊类型的方法, 因为他没有返回值。这与返回值为空(void)明显不同。对于空返回值,尽管方法本身不会自动返回什么, 但仍可选择让他返回别的东西。
- 思考: void还可以返回别的东西? 是什么东西呢? 后来想到, 可能是void可以通过return ;返回. 也就是可以截断下面的流程. 而构造函数不可以, 他必须将其全部执行完毕才能退出方法. return; 就是返回void的.
 
2. 方法重载
- 方法重载的条件
- 名字相同
- 参数列表类型或个数不同
 
- 基本类型重载的问题
- 基本类型能从一个“较小”的类型自动提升至一个“较大“的类型. 此过程一旦涉及到重载, 可能会出现混淆。看下面这个例子
package net.mindview.initialization; 
 import static net.mindview.util.Print.*;
 public class PrimitiveOverloading { void f1(char x) {print("f1(char)");}
 void f1(byte x) {print("f1(byte)");}
 void f1(short x) {print("f1(short)");}
 void f1(int x) {print("f1(int)");}
 void f1(long x) {print("f1(long)");}
 void f1(float x) {print("f1(float)");}
 void f1(double x) {print("f1(double)");} void f2(byte x) {print("f2(byte)");}
 void f2(short x) {print("f2(short)");}
 void f2(int x) {print("f2(int)");}
 void f2(long x) {print("f2(long)");}
 void f2(float x) {print("f2(float)");}
 void f2(double x) {print("f2(double)");} void f3(short x) {print("f3(short)");}
 void f3(int x) {print("f3(int)");}
 void f3(long x) {print("f3(long)");}
 void f3(float x) {print("f3(float)");}
 void f3(double x) {print("f3(double)");} void f4(int x) {print("f4(int)");}
 void f4(long x) {print("f4(long)");}
 void f4(float x) {print("f4(float)");}
 void f4(double x) {print("f4(double)");} void f5(long x) {print("f5(long)");}
 void f5(float x) {print("f5(float)");}
 void f5(double x) {print("f5(double)");} void f6(float x) {print("f6(float)");}
 void f6(double x) {print("f6(double)");} void f7(double x) {print("f7(double)");} /**测试常量*/
 void testConstVal(){
 print("5:");
 f1();f2();f3();f4();f5();f6();f7();println("");
 } /**测试char*/
 void testChar(){
 char x = 'x';
 print("char:");
 f1(x);f2(x);f3(x);f4(x);f5(x);f6(x);f7(x);println("");
 } /**测试byte*/
 void testByte(){
 byte x = ;
 print("byte:");
 f1(x);f2(x);f3(x);f4(x);f5(x);f6(x);f7(x);println("");
 } /**测试Short*/
 void testShort(){
 short x = ;
 print("short:");
 f1(x);f2(x);f3(x);f4(x);f5(x);f6(x);f7(x);println("");
 } /**测试Int*/
 void testInt(){
 int x = ;
 print("int:");
 f1(x);f2(x);f3(x);f4(x);f5(x);f6(x);f7(x);println("");
 } /**测试long*/
 void testLong(){
 long x = ;
 print("long:");
 f1(x);f2(x);f3(x);f4(x);f5(x);f6(x);f7(x);println("");
 } /**测试double*/
 void testDouble(){
 double x = ;
 print("double:");
 f1(x);f2(x);f3(x);f4(x);f5(x);f6(x);f7(x);println("");
 } public static void main(String[] args) {
 PrimitiveOverloading p = new PrimitiveOverloading();
 p.testConstVal();
 p.testChar();
 p.testByte();
 p.testShort();
 p.testInt();
 p.testLong();
 p.testDouble(); } }执行结果: :f1(int)f2(int)f3(int)f4(int)f5(long)f6(float)f7(double) 
 char:f1(char)f2(int)f3(int)f4(int)f5(long)f6(float)f7(double)
 byte:f1(byte)f2(byte)f3(short)f4(int)f5(long)f6(float)f7(double)
 short:f1(short)f2(short)f3(short)f4(int)f5(long)f6(float)f7(double)
 int:f1(int)f2(int)f3(int)f4(int)f5(long)f6(float)f7(double)
 long:f1(long)f2(long)f3(long)f4(long)f5(long)f6(float)f7(double)
 double:f1(double)f2(double)f3(double)f4(double)f5(double)f6(double)f7(double)结论: 有int, 则执行对应的int方法, 如果没有, 则向上转型,执行最近的方法, 其他char, byte, short,int, long, double都是如此. 其中char有所不同, 如果无法找到恰好是接收char参数的方法,就会把char提升至int值. 
- 如果参数是一个较大的类型, 就需要通过强转为一个较小的类型后才能使用,否则,编译报错.
 
- 基本类型能从一个“较小”的类型自动提升至一个“较大“的类型. 此过程一旦涉及到重载, 可能会出现混淆。看下面这个例子
- 为何不能以返回值来区分方法的重载
- 因为有时候 ,我并不关心方法的返回值, 我想要的是方法调用的其他效果(这场被称为""为了副作用而调用"), 这时你可能会调用方法而忽略了其返回值。例如:定义了两个方法
void f(){};
 int f(){return };而我在调用的时候并不关心他的返回值 f(); 
 
- 因为有时候 ,我并不关心方法的返回值, 我想要的是方法调用的其他效果(这场被称为""为了副作用而调用"), 这时你可能会调用方法而忽略了其返回值。例如:定义了两个方法
4. this关键字
- this关键字只能在方法内部使用, 表示对"调用方法的那个对象"的引用.
- 只有当需要明确指出对当前对象的引用时, 才需要使用this关键字. 例如, 当需要返回堆当前对象的引用时, 就常常在return语句中这样写:
public class Leaf { int i = ;
 Leaf increment() {
 i++;
 return this;
 }
 }注意: this不是指当前类, 而是当前类的对象. 
- 使用this调用构造器
- 在构造器中调用构造器, 使用this;
- 在构造器调用另一个构造器, 只能调用一次.并且将this调用置于最起始处.
- 除了在构造器中可以调用构造器外, 禁止在该类的其他地方调用构造器.
 
- static的含义
- 理解了this的作用, 有助于理解static(静态)方法的含义
- static方法就是没有this的方法
- static方法的内部不能调用非static的方法
- 因为static方法类似于全局方法, 只有一份. 也就是公共的, 内容不可变
- 非静态方法是每个类对象独有的, 参数, 含义都是对象独有, 方法内容会有变化. 所以, static方法不能调用非static方法
 
- static方法内部可以访问static方法和static成员变量.
- 要是在代码中出现大量的static方法, 就该重新考虑自己的设计了.
- 原因: static方法具有全局函数的含义, 使用static方法,不能使用this, 所以不是通过"面向对象的方式发送消息"
 
 
5. 垃圾回收器
- 垃圾回收器负责回收对象占用的内存资源。
- 垃圾回收器也有不能回收的“特殊的”内存资源。假定你的对象获得了一个“特殊”的内存资源, 由于垃圾回收器只知道负责释放那些经由new分配的内存, 所以他不知道该如何释放该对象的这块“特殊”内存。为了应对这种情况,java允许在类中定义一个名为finalize()的方法。
- finalize()方法的工作原理"假定"是这样:一旦垃圾回收器准备好释放对象占用的存储空间,将首先调用 finalize()方法,并且在下一次垃圾回收动作发生时,才会真正回收对象占用的内存。所以你要打算调用finalize(),就能在垃圾回收时做一些重要的清理工作。
- 垃圾回收只与内存有关:
- java里的垃圾并不总是被垃圾回收, 调用了finalize()方法, 也不一定会立即生效, 这时垃圾处理机制决定的。 通常只有内存濒临耗完时才会调用垃圾回收机制。finalize()方法才会最终生效. 因为垃圾回收本身也会消耗资源.
 
- 普通的清理工作不适合finalize()
- 通常类中不必定义finalize()方法来主动销毁对象. 只有一种情况需要finalize(),即通过某种创建对象方式以外的方式为对象分配存储空间。可我们都知道, java中一切接对象,那么这种“特殊”情况又是怎么回事呢?
- 这种情况通常发生在java的"本地方法"的情况。本地方法是一种在java中调用非java代码的方式。
 
- finalize()的用武之地:对象终结条件的验证。
- 对象终结条件是怎么回事呢? 当一个对象没有用的时候, 也就是他应该被清理的时候。这个对象应该处于某种状态, 让他占用的内存完全被安全地释放。例如:对象代表了打开文件, 当对象被回收前,程序员应该关闭打开的这个文件。那么,如果,一个文件被打开了, 却没有被关闭, 这样就会导致垃圾回收器不能回收这块资源。久而久之就会导致内存的溢出。 这是程序的缺陷。 这时如果在垃圾回收的时候执行了finalized()方法, 这个缺陷就可能会被发现, 具体看下面的例子。
package net.mindview.initialization; class Book{
 boolean checkedOut = false;
 Book(boolean checkedOut){
 this.checkedOut = checkedOut;
 } void checkIn(){
 checkedOut = false;
 } protected void finzlized() throws Throwable {
 if(checkedOut){
 System.out.println("有书被借走但未归还 ");
 //基类版本的finalize()也要做一些重要的事, 应使用super来调用.
 super.finalize();
 }
 }
 } public class TerminationCondition {
 public static void main(String[] args) {
 Book novel = new Book(true);
 //合理的清理
 novel.checkIn();
 //书被借出后, 没有归还
 new Book(true);
 //强制垃圾回收并且执行finalized方法
 System.gc();
 }
 }本例的总结条件,应该是,被签出的图书全部被签入.也就是说借出的书应该全部被归还. 但在main方法中, 程序员错误的将图书借出了,但此书未被归还。但程序却没有任何错误。 这种问题一旦存在了, 很难被程序员自己发现。 直到最后内存溢出,调用finalize()方法,我们才知道。这里finalize就是用来验证终结条件的。 
- 再解释一下上面的案例: 一个对象能够被清理, 条件是没有地方在使用它了。 如果一个对象是打开文件, 使用了, 就应该关闭文件, 如果没有关系, 这个对象就不能被回收, 久而久之必然导致内存的耗尽, jvm就会调用垃圾回收期回收对象。这时如果程序员手动定义了finalize()方法, 那么当垃圾回收时, 他就会发现内存溢出的原因在哪里了。所以, 在某种情况下定义finalize()方法是一个好的喜欢.
 
- 对象终结条件是怎么回事呢? 当一个对象没有用的时候, 也就是他应该被清理的时候。这个对象应该处于某种状态, 让他占用的内存完全被安全地释放。例如:对象代表了打开文件, 当对象被回收前,程序员应该关闭打开的这个文件。那么,如果,一个文件被打开了, 却没有被关闭, 这样就会导致垃圾回收器不能回收这块资源。久而久之就会导致内存的溢出。 这是程序的缺陷。 这时如果在垃圾回收的时候执行了finalized()方法, 这个缺陷就可能会被发现, 具体看下面的例子。
6. 成员初始化
- 类成员
- 基本类型的成员变量, 如果在定义的时候没有初始化, 系统会自动初始化为对应类型的默认值.
- 对象应用类型如果在定义的时候没有被初始化, 此引用就会获得一个特殊的值null.
 
7.构造器初始化
- 静态数据初始化
- 无论创建多少个对象, 静态数据都只占用一份存储区域。
- 静态数据何时被初始化? 静态数据所在的类被实例化的时候初始化。
- 静态数据初始化的顺序在非静态数据之前。也就是说,一个类中有静态成员变量和非静态成员变量, 他们初始化的顺序是,先静态成员,在非静态成员
 
- 显示的静态成员初始化--静态块
package net.mindview.initialization; public class Spoon {
 static int i;
 static {
 i = ;
 }
 public static void main(String[] args) {
 // TODO Auto-generated method stub }
 }- 可以再静态代码块中初始化静态成员变量.
- 静态代码块只会被第一次new的时候执行一次
- 静态块只能 初始化静态成员变量, 不能初始化非静态成员变量
public class Test14 {
 public static String str1 = "abc";
 public static String str2;
 public String str3;
 static {
 str2 = "def";
 //str3 = "aaa"; //报错
 }
 }
- 为什么需要静态代码块, 将代码直接写在构造方法里不可以么?
- 原因是, 如果一个方法是静态方法, 就可以通过类名.方法名来调用这个方法, 也就是不会被new, 不被new, 因此就不会调用构造方法. 这时, 如果想要在调用静态方法之前执行一些操作, 就要在静态代码块中定义了
 
 
- 非静态成员变量初始化
- 和静态成员初始化一模一样, 就是去掉static关键字
- 在构造函数执行之前执行
package net.mindview.initialization; public class Test14 {
 public static String str1 = "abc";
 public static String str2;
 public String str3; //静态成员初始化
 static {
 str2 = "def";
 //str3 = "aaa"; //报错
 } //非静态成员初始化
 {
 str3 = "aaa";
 str2 = "mmm";//也可以给静态成员初始化
 }
 public static void print(){
 System.out.println("str1 :"+ str1);
 System.out.println("str2 :"+ str2);
 }
 public static void main(String[] args) {
 Test14 t = new Test14();
 print();
 System.out.println("str3 :"+ t.str3);
 }
 }这个例子说明如下问题: - 非静态初始化块中可以为静态成员变量赋值
- 当静态块和非静态快同时存在时, 静态块先执行, 非静态快后执行
 
 
8. 可变参数列表
package net.mindview.initialization;
public class NewVarArgs {
    static void printArray(Object ... args){
        for(Object arg: args) {
            System.out.print(arg + "");
        }
        System.out.println("");
    }
    public static void main(String[] args) {
        printArray(new Integer(), new Float(3.14), new Double(2.333));
        printArray((Object[])new Integer[]{,,,});
        printArray();
    }
}
- 使用 ...的方式定义可变数组
- 当指定参数时, 编译器实际上会自动填充为一个数组,你获取的仍旧是一个数组, 因此可以再方法内部使用foreach循环打印
- 当参数本身就是一个数组时, 编译器直接接受这个数组
- 可变参数必须是方法的最后一个参数
- 可变参数可以和自动包装机制和谐相处。
- 参数是Integer类型, 如果换地过来的是int类型, 可以自动转换
 
- 可变参数的重载
- 可变参数会使用自动包装机制来匹配重载方法, 然后调用最明确匹配的方法。
 
9. 枚举类型
package net.mindview.initialization;
enum Spiciness {
    NOT,MILD,MEDIUM,HOT,FALMING
}
public class SimpleEnumUse {
    public static void main(String[] args) {
        Spiciness falming = Spiciness.FALMING;
        System.out.println(falming);
    }
}
- 枚举定义使用enum关键字
- 枚举类型的实例是常量, 所以命名要求全部大写.
- 在创建enum时, 编译器会自动添加一些使用的特性. 
- 自动创建toSring()方法,以便可以很方便的显示enum实例的名字,这正是上面可以产生其输出答案的原因。
- 自动生成oridinal()方法: 用来表示enum常量声明的顺序
- 自动生成static value()方法:按照enum生成的顺序, 产生有这些常量构成的数组.
package net.mindview.initialization; enum Spiciness {
 NOT,MILD,MEDIUM,HOT,FALMING
 } public class SimpleEnumUse {
 public static void main(String[] args) {
 for(Spiciness s: Spiciness.values()){
 System.out.println(s + ", " + s.ordinal());
 }
 }
 }
- enum是在有限的集合中进行选择, 因此其与switch是绝佳组合.
package net.mindview.initialization; enum Spiciness {
 NOT,MILD,MEDIUM,HOT,FALMING
 } public class SimpleEnumUse {
 public static void main(String[] args) {
 Burrito plain = new Burrito(Spiciness.HOT);
 Burrito greenChile = new Burrito(Spiciness.MEDIUM);
 Burrito jalapeno = new Burrito(Spiciness.NOT); plain.describe();
 greenChile.describe();
 jalapeno.describe();
 }
 } class Burrito {
 Spiciness degree;
 public Burrito(Spiciness degree){
 this.degree = degree;
 } public void describe(){
 switch(degree){
 case NOT:
 System.out.println("not");
 break;
 case MILD:
 case MEDIUM:
 System.out.println("medium");
 break;
 case HOT:
 System.out.println("hot");
 break;
 case FALMING:
 default:
 System.out.println("falming");
 break;
 }
 }
 }
 
java编程思想第四版第五章总结的更多相关文章
- java编程思想第四版第五章习题
		创建一个类, 它包含一个未初始化的String引用.验证该引用被Java初始化成了null package net.mindview.initialization; public class Test ... 
- Java编程思想第四版 *第五章 个人练习
		练习3:(1)创建一个带默认构造器(即无參构造器)的类.在构造器中打印一条消息.为这个类创建一个对象.P116 public class Test{ public Test(){ System.out ... 
- java编程思想第四版第十三章字符串  习题
		fas 第二题 package net.mindview.strings; import java.util.ArrayList; import java.util.List; /** * 无限循环 ... 
- java编程思想第四版第十一章习题
		第一题 package net.mindview.holding.test1; import java.util.ArrayList; import java.util.List; /** * 沙鼠 ... 
- Java编程思想第四版*第七章*个人练习
		欢迎加群:239063848 成团的笔记:该组仅用于技术共享和交流,问题和答案公布 潘基聊天.禁止广告.禁止招聘-- 练习1:(2)创建一个简单的类.第二个类中,将一个引用定义为第一个类的对象.运用惰 ... 
- java编程思想第四版第六章习题
		(略) (略) 创建两个包:debug和debugoff,他们都包含一个相同的类,该类有一个debug()方法,第一个版本显示发送给控制台的String参数,而第二版本什么也不做,使用静态import ... 
- java编程思想第四版第六章总结
		1. 代码重构 为什么f要代码重构 第一次代码不一定是完美的, 总会发现更优雅的写法. 代码重构需要考虑的问题 类库的修改不会破坏客户端程序员的代码. 源程序方便扩展和优化 2. 包 创建一个独一无二 ... 
- java编程思想 第四版 第六章 个人练习
		欢迎加群:239063848 进群须知:本群仅用于技术分享与交流.问题公布与解答 禁止闲聊.非诚勿扰 练习1:(1)在某个包中创建一个类,在这个类所处的包的外部创建该类的一个实例. import mi ... 
- java编程思想第四版第十三章字符串  总结
		1. String和StringBulider的使用 通过书中介绍, 我们得知如下结论: 当使用+连接符将字符串进行拼接的时候, 编译器会进行自动优化为使用StringBuilder连接字符串. 当在 ... 
随机推荐
- 攻防世界(XCTF)WEB(进阶区)write up(四)
			ics-07 Web_php_include Zhuanxv Web_python_template_injection ics-07 题前半部分是php弱类型 这段说当传入的id值浮点值不能为1 ... 
- CSS Grid 网格布局教程
			一.概述 网格布局(Grid)是最强大的 CSS 布局方案. 它将网页划分成一个个网格,可以任意组合不同的网格,做出各种各样的布局.以前,只能通过复杂的 CSS 框架达到的效果,现在浏览器内置了. 上 ... 
- LeetCode 2: single-number II
			Given an array of integers, every element appears three times except for one. Find that single one. ... 
- VirtualBox NAT Network配置
			VirtualBox NAT Network配置(OSX上的) VirtualBox的5种连接方式 NAT :虚拟机之间不能互通 NAT网络 :本文对象 桥接 :一般情况下虚拟机无法设置静态IP,并且 ... 
- 设计模式(八)Abstract Factory模式
			抽象工厂的工作是将“抽象零件”组装为“抽象产品”.在抽象工厂模式中将会出现抽象工厂,它会将抽象零件组装为抽象产品.也就是说,我们并不关心零件的具体实现,而是只关心接口.我们仅适用该接口将零件组装起来成 ... 
- Redis(十三)Python客户端redis-py
			一.安装redis-py的方法 使用pip install安装redis-py C:\Users\BigJun>pip3 install redis Collecting redis Downl ... 
- Redis(二)数据结构与键管理
			一.基础知识 1.全局命令 keys * :查看所有键 dbsize:返回当前数据库中键的总数 exists key:检查键是否存在 del key ... :删除键 expire key sec ... 
- 如何在Spring Boot中使用Cookies
			一. 导读 本文大纲 读取HTTP Cookie 设置HTTP Cookie 读取所有Cookie[] 为Cookie设置过期时间 Https与Cookie HttpOnly Cookie 删除Coo ... 
- 如何在Spring Boot项目中巧妙利用策略模式干掉if else!
			直入主题 我们都知道,设计模式(Design Pattern)是前辈们对代码开发经验的总结,是解决特定问题的一系列套路.它不是语法规定,而是一套用来提高代码可复用性.可维护性.可读性.稳健性以及安全性 ... 
- Spring IoC的概念
			Spring IoC的基础知识 Spring 框架可以说是Java世界中最成功的框架,它的成功来自于理念,而不是技术,它最核心的理念是IoC(控制反转)和AOP(面向切面编程),其中IoC是Sprin ... 
