第2章 Java内存区域与内存溢出异常

本章从概念上介绍Java虚拟机内存的各个区域,讲解这些区域的作用、服务对象以及其中可能产生的问题。

一、运行时数据区域

1、程序计数器

程序计数器是一块较小的内存空间,可以看作是当前线程所执行的字节码的行号指示器。在虚拟机的概念模型里,字节码解释器工作时就是通过改变这个计数器的值来选取下一条需要执行的字节码指令,分支、循环、跳转、异常处理、线程恢复等基础功能都需要依赖这个计数器来完成。

继续阅读“第2章 Java内存区域与内存溢出异常”

Java零散知识点

1、Java是值传递的

①对于基本数据类型short、int、long、float、double、char、byte、boolean这八种按值传递调用函数并不会改变在原函数中的值。

② 对于引用数据类型数组、类、接口按值传递的时候都是传递对象的地址,方法体内改变形参的引用,不会改变实参的引用,但有可能改变实参对象的属性值。

public class Demo {
    public static void main(String[] args) {

        //demo1
        String str = "hello";
        char[] chs = {'w','o','r','l','d'};
        change(str, chs);
        System.out.println(str + " " + new String(chs));
        //输出“hello World”

        //demo2
        StringBuffer sb = new StringBuffer("hello");
        change(sb);
        System.out.println(sb);
        //输出“hello world”
    }

    public static void change(StringBuffer sb) {
        sb.append(" world");
        //此处的sb与main方法中的sb指向同一个对象,改变了对象的内容 
    }

    public static void change(String str, char[] chs) {
        str.replace('h', 'H');
        //因为String的不可变性,此处str指向对象的内容没有发生变化
        //str = str.replace('h', 'H');
        //此处str指向内容为“Hello”的对象,不改变main方法中str的指向

        chs[0] = 'W';
        //此处的chs与main方法中的chs指向同一个对象,改变了对象的内容
    }
}
继续阅读“Java零散知识点”

第2章 创建和销毁对象

本章的主题是创建和销毁对象:何时以及如何创建对象,何时以及如何避免创建对象,如何确保它们能够适时地销毁,以及如何管理对象销毁之前必须进行的各种清理动作。


第一条:用静态工厂方法代替构造器

类为了让客户端获取它自身的一个实例,最传统的方法是提供一个公有的构造器。除此之外,类可以提供一个公有的静态工厂方法,它只是一个返回类的实例的静态方法。

/**
 * 一个来自Boolean(基本类型boolean的装箱类)的简单示例,
 * 该方法将boolean基本类型值转换成了一个Boolean对象引用。
 */
public static Boolean vauleOf(boolean b) {
    return b ? Boolean.TURE : Boolean.FALSE;
}

提供静态工厂方法而不是公有的构造器,这样做既有优势,也有劣势。

继续阅读“第2章 创建和销毁对象”

策略模式

书中以模拟鸭子的应用为例引出策略模式,方便理解。

模拟鸭子游戏:游戏中会出现各种鸭子,一边游泳戏水,一边呱呱叫。此系统设计了一个鸭子超类(Superclass),并让各种鸭子继承此超类。

abstract class Duck {
/**
* 所有的鸭子都会呱呱叫(Quack)也会游泳(Swim),
* 所以由超类负责处理这部分的实现代码。
*/
public void quack() {};
public void swim() {};
//每一种鸭子的外观都不同,所以display()方法是抽象的。
public abstract void display();
}
/**
* 每个鸭子子类型(subtype)负责实现自己的display()行为,
* 在屏幕上显示其外观。
*/
class MallardDuck extends Duck {
@Override
public void display() {
//外观是绿头
}
}
/**
* 许多其他类型的鸭子继承Duck类。
*/
class RedheadDuck extends Duck {
@Override
public void display() {
//外观是红头
}
}
继续阅读“策略模式”

Java多线程机制

一、线程的基本概念
1. 线程是一个程序内部的顺序控制流。
2. 线程和进程的区别
①每个进程都有独立的代码和数据空间(进程上下文),进程间的切换会有较大的开销。
②线程可以看成是轻量级的进程,同一类线程共享代码和数据空间,每个线程有独立的运行栈和程序计数器(PC),线程切换的开销小。
③多进程:在操作系统中能同时运行多个任务(程序)
④多线程:在同一应用程序中有多个顺序流同时执行
3. Java的线程是通过java.lang.Thread类来实现的。
4. VM启动时会有一个由主方法(public static void main() {})所定义的线程。
5. 可以通过创建Thread的实例来创建新的线程。
6. 每个线程都是通过某个特定Thread对象所对应的方法run()来完成其操作的,方法run()称为线程体。
7. 通过调用Thread类的start()方法来启动一个线程。

二、线程的创建和启动
1. 可以有两种方法创建新的线程
①第一种

1.定义线程类实现Runnable接口
2.Thread myThread = new Thread(target); //target为Runnable接口类型
3.Runnable中只有一个方法:
public void run();用以定义线程运行体。
4.使用Runnable接口可以为多个线程提供共享的数据。
5.在实现Runnable接口的类的run方法定义中可以使用Thread的静态方法:
public static Thread currentThread();获取当前线程的引用。

②第二种

1.可以定义一个Thread的子类并重写其run方法,如:
class MyThread extends Thread {
public void run() {
...
}
}
2.然后生成该类的对象:
MyThread myThread = new MyThread(...);san
继续阅读“Java多线程机制”

Java流

一、Java流式输入/输出原理

在Java程序中,对于数据流的输入/输出操作以“流”(stream)方式进行。
JDK提供了各种各样的“流”类,用以获取不同种类的数据。
程序中通过标准的方法输入或输出数据。

二、输入/输出流的分类
1. java.io包中定义了多个流类型(类或抽象类)来实现输入/输出功能,可以从不同的角度对其进行分类:
①按数据流的方向不同可以分为输入流和输出流。
②按处理数据单元不同可以分为字节流和字符流。
③按功能不同可以分为节点流和处理流。
2. JDK所提供的所有流类型位于包java.io内都分别继承自以下四种抽象流类型:

字节流字符流
输入流InputStreamReader
输出流OutputStreamWriter
继续阅读“Java流”

Java常用类

一、字符串相关类
1. String类
①java.lang.String类代表不可变的字符序列。
②“xxxxx”为该类的一个对象。
③String类的常见构造方法:

  • String(String original):创建一个String对象为original的拷贝。
  • String(char[] value):用一个字符数组创建一个String对象。
  • String(char[] value, int offset, int count):用一个字符数组从offset项开始的count个字符序列创建一个String对象。

2. StringBuffer类
①java.lang.StringBuffer类代表可变的字符序列。
②StringBuffer和String类似,但StringBuffer可以对其字符串进行改变。
③StringBuffer类的常见构造方法:

  • StringBuffer():创建一个不包含字符序列的“空”的StringBuffer对象。
  • StringBuffer(String str):创建一个StringBuffer对象,包含与String对象str相同的字符序列。

二、基本数据类型包装类
1. 包装类(如:Integer,Double等)封装了一个相应的基本数据类型数值,并为其提供了一系列操作。
2. 以java.lang.Integer类为例,构造方法:

  • Integer(int value)
  • Integer(String s)
继续阅读“Java常用类”

Java数组

一、数组概述
1. 数组可以看成是多个相同类型数据组合,对这些数据的统一管理。
2. 数组变量属引用类型,数组也可以看成是对象,数组中的每个元素相当于该对象的成员变量。
3. 数组中的元素可以是任何数据类型,包括基本类型和引用类型。

二、一维数组
1. 一维数组的声明

type[] var; 

* type var[ ];也可以,但Java中推荐type[ ] var;
* Java语言中声名数组时不能指定其长度(数组中元素的个数),如int a[5];是非法的。
2. 数组对象的创建
Java中使用关键字new创建数组对象,格式为:
数组名 = new 数组元素的类型[数组元素的个数];
* 例如:

public class Test {
public static void main(String[] args) {
int[] s;
s = new int[5];
}
}

* 注意:元素为引用数据类型的数组中的每一个元素都需要实例化。

继续阅读“Java数组”

Java异常处理

一、Java异常的概念
1. Java异常是Java提供的用于处理程序中错误的一种机制。
2. 所谓错误是指在程序运行的过程中发生的一些异常事件(如:除0溢出,数组下标越界,所要读取的文件不存在)。
3. 设计良好的程序应该在异常发生时提供处理这些错误的方法,使得程序不会因为异常的发生而阻断或产生不可预见的结果。
4. Java程序的执行过程中如出现异常事件,可以生成一个异常类对象,该异常对象封装了异常事件的信息并将被提交给Java运行时系统,这个过程称为抛出(throw)异常。
5. 当Java运行时系统接收到异常对象时,会寻找能处理这一异常的代码并把当前异常对象交给其处理,这一过程称为捕获(catch)异常。

二、Java异常的分类

Java中定义了很多异常类,这些类对应了各种各样可能出现的异常事件。
  • Error:称为错误,由Java虚拟机生成并抛出,包括动态链接失败、虚拟机错误等,程序对其不做处理。
  • Exception:所有异常类的父类,其子类对应了各种各样可能出现的异常事件,一般需要用户显式的声明或捕获。
  • Runtime Exception:一类特殊的异常,如被0除、数组下标超范围等,其产生比较频繁,处理麻烦,如果显式的声明或捕获将会对程序可读性和运行效率影响很大。因此由系统自动检测并将它们交给缺省的异常处理程序(用户可不必对其处理)。
继续阅读“Java异常处理”

Java容器

一、容器的概念
Java API所提供的一系列类的实例,用于在程序中存放对象。位于java.util包内。

二、容器框架图
Java 集合框架主要包括两种类型的容器,一种是集合(Collection),存储一个元素集合,另一种是图(Map),存储键/值对映射。Collection 接口又有 3 种子类型,List、Set 和 Queue,再下面是一些抽象类,最后是具体实现类,常用的有 ArrayList、LinkedList、HashSet、LinkedHashSet、HashMap、LinkedHashMap 等等。

继续阅读“Java容器”