Java核心技术摘要

每天Java后台都来问我一些简单的样式问题和一些js不为人轻易发现的问题。那我也要问他们一些简单的Java问题。哈哈哈。

面向对象程序设计
反射与代理
接口与内部类
异常处理
泛型程序设计
集合框架
事件监听器模型
使用 Swing UI 工具箱进行图形用户界面设计
并行操作

类是一个加载程序逻辑的容器,程序逻辑定义了应用程序的行为。类是构建所有Java程序和applet的构建块,Java应用程序中的全部内容都必须放置在类中。每个单词的第一个字母应该大写。源代码的文件名必须与公共类的名字相同,并用.java作为扩展名。编译后会得到.class 文件,与源文件在同一个目录下。运行已经编译的程序时,Java虚拟机将从指定类中的main方法开始执行,为了代码能够执行,在类的源文件中必须包含一个main方法。当然,也可以将用户自定义的方法添加到类中,并且在main方法中调用他们。main方法声明为public。回车不是语句结束的标志,如果需要可以将一条语句写在多行上。Java是一种强类型的语言,这就意味着必须为每一个变量声明类型。(js是弱类型的语言,不必声明类型)。

1
2
3
4
5
6
7
public class ClassName
{
public static void main(String[] args)
{
program statements
}
}

在Java中,一共有8种基本类型(primitive type),其中有4种整型,2种浮点型,1种用于表示Unicode编码的字符单元的字符类型char和1种用于表示真值的Boolean类型.

1
2
3
4
字节位相关知识
1字节 8位 第一位为符号位 -2^(8-1) ~ 2^(8-1)
1111 1111
d0111 1111 第一位为0表示正数,最大为127

4种整型:
int     4字节(32位)    超过20亿
short   2字节(16位)
long    8字节(64位)
byte    1字节(8位)

由于Java程序必须保证在所有机器上都能够得到相同的运行结果,所以各种数据类型的取值范围必须固定.长整型数值有一个后缀L或l(40000000000000L).十六进制数值有一个前缀0X或0x(0xcafe).八进制有一个前缀0,如010,八进制表示法比较容易混淆,所以建议最好不要使用八进制常数.从Java7开始,加上前缀0b或者0B可以写二进制数.还可以为数字字面量加下划线,如1_000_000表示一百万,Java编译器会除去这些下划线.Java中没有任何无符号形式的int long short byte类型.

浮点类型

浮点类型用于表示小数部分的数值.在Java中有俩种浮点类型.
float(单精度)  4字节     (小数点有效位数为6~7)
double(双精度) 8字节     (有效位数为15位)
float类型的数值有一个后缀F或f,没有后缀F的浮点数值(如3.14)默认为double类型.
所有的浮点数值计算都遵循IEEE 754规范,有三种表示溢出和出错情况的三个特殊的浮点数值:
正无穷大    
负无穷大
NaN(不是一个数字,如0/0,所有的非数值都是不相同的.)
浮点数值不适用于无法接受舍入误差的金融计算中.例如System.out.println将打印出0.8999999999,而不是人们想象的0.9.这种舍入误差的主要原因是浮点数值采用2进制无法精确的表示分数1/10.这就好像十进制数无法精确表示分数1/3一样.如果在计算中不允许有任何舍入误差,就应该使用BigDecimal类.

char类型原本用于表示单个字符.如今,有些Unicode字符可以用一个char表示,另外一些Unicode字符则需要俩个char值.

Boolean类型

false
true
用来判断逻辑条件.整型值和布尔值之间不能相互转换.

变量

在Java中,每个变量都有一个类型(type).在声明变量时,变量的类型位于变量名之前.
double salary;
int vacationDays;
long earthPopulation;
boolean done;
每个声明是一条完整的Java语句,所以必须以分号结束.变量名必须是一个以字母开头并由数字构成的序列.Java字母包括'A'~'Z','a'~'z','_','$'或在某种语言中表示字母的任何Unicode字符.

在Math类中,包含了各种各样的数学函数.在编写不同类别的程序时,可能需要的函也不同.
要想计算一个数值的平方根,可以使用sqrt方法:
double x = 4;
double y = Math.sqrt(x);
System.out.println(y); // print 2.0
println方法和sqrt方法存在微小的差异,println方法处理System.out对象.但是,Math类中的sqrt方法处理的不是对象,这样的方法被称为静态方法.

类型转换规则

如果俩个操作数中有一个是double类型,则另一个操作数会转换为double类型.
否则,如果其中一个是float类型,另一个操作数将会转换为float类型.
否则,如果其中一个操作数是long类型,另一个操作数将会转换为long类型.
否则俩个操作数都将会转换为int类型
1
2
3
4
5
//上面是自动转换机制,小类型自动转换大类型.
//强制转换机制: 在圆括号中给出想要转换的目标类型,后面紧跟待转换的变量名.
double x=9.997;
int nx=(int) x; //强制类型转换通过截断小数部分将浮点值转换为整型
// warn: 如果试图将一个数值从一种类型强制转换为另一种类型,而又超出了目标类型的表示范围,结果就会截断为一个完全不同的值.(byte) 300的实际值为44.

自增自减运算符会改变变量的值,所以他们的操作数不能是数值.例如4++就不是一个合法的语句.

异或: 男性和女性才能生孩子(囧); 位掩码技术
左位移: n << m => n*2^m
右位移: n >> m => n/2^m
int fourthBitFormRight = (n & 0b10000 )/0b10000;
int fourthBitRight = (n & (1<<3)) >> 3;

自定义枚举类型: 枚举类型包括有限个命名的值
enum Size {SMALL,MEDIUM,LARGE,EXTRA_LAGER};
Size s=Size.MEDIUM;
字面量: 未经过声明赋值直接使用的变量.
char数据类型是一个采用UTF-16表示Unicode码点的代码单元.length方法将返回采用UTF-16编码表示的给定字符串所需要的代码单元的数量.
打印到标准输出流(控制台窗口),调用System.out.println即可.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class Retirement
{
public static void main(String[] args)
// read inputs
{
Scanner in = new Scanner(System.in);
System.out.println("how much money will you need to retire?");
double goal = in.nextDouble();
System.out.println("How much money will you contribute every year?");
double payment = in.nextDouble();
System.out.print("Interest rate in %:");
double interestRate = in.nextDouble();
double balance=0;
int years =0;
// update account balance while goal isn't reached
while(balance < goal ){
balance += payment;
double interest = balance * interestRate/100;
balance+=interest;
years++;
}
System.out.println("you are retire"+years+"years.");
}
}

如果基本的整数和浮点数精度不能够满足需求,可以使用Java.math中的俩个很有用的类:BigInteger和BigDecimal.这俩个类可以处理包含任意长度数字序列的数值.BigInteger类实现了任意精度的整数运算,BigDecimal实现了任意精度的浮点运算.使用静态的valueOf方法可以将普通的数值转换为大数值.
BigInteger a = BigInteger.valueOf(100)

数组是一种数据结构,用来存储同一类型值的集合.在声明数组变量的时候要指出数组类型(数据元素类型紧跟[])和数组变量的名字.
声明整型数组a:
int[] a;
new 运算符创建数组(创建了一个可以存储100个整数的数组,所有元素的初始化都为0):
int[] a = new int[100];

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import java.util.*;
public class LotteryDrawing
{
public static void main(String[] args)
{
Scanner in = new Scanner(System.in);
System.out.print("How many numbers do you need to draw?");
int k = in.nextInt();
System.out.print("what is the highest number you can draw?");
int n = in.nextInt();
int[] numbers = new int[n];
for(int i=0;i<numbers.length;i++){
numbers[i] = i+1;
}
int[] result = new int[k];
for(int i=0;i<result.length;i++){
int r=(int)(Math.random()*n);
result[i]=numbers[r];
numbers[r]=numbers[n-1];
n--;
}
Array.sort(result);
System.out.println("bet the following combination.It'll make you rich");
for(int r : result)
System.out.println(r);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public class LotteryArray
{
public static void main(String[] args)
{
final int NMAX = 10;
// allocate triangular array
int[][] odds = new int[NMAX+1][];
for(int n=0;n<=NMAX;n++){
odds[n]=new int[n+1];
}
for(int n=0;n<odds.length;n++){
for(int k=0;k<odds[n].length;n++){
int lotteryOdds = 1;
for(int i=1; i<=k;i++){
lotteryOdds = lotteryOdds*(n-i+1)/i;
}
odds[n][k] = lotteryOdds*(n-i+1)/i;
}
}
for(int[] row : odds){
for(int odd: row){
System.out.printf("%4d",odd);
}
System.out.println();
}
}
}

对象与类型

面向对象程序设计      对象构造
使用预定义类         包
用户自定义类          类路径  
静态域与静态方法      文档注释
方法参数             类设计技巧

对象的行为: 可以对对象施加哪些操作,或可以对对象施加哪些方法?
对象的状态: 当施加哪些方法时,对象如何响应?
对象标识: 如何辨别具有相同行为与状态的不同对象?

在一个源文件中,只能有一个公有类,但可以有任意数目的非公有类.当编译这段代码的时候,编译器将在目录下创建俩个类文件,EmployeeTest.class和Employee.class

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
import java.time.*;
public class EmployeeTest
{
public static void main(String[] args){
// fill the staff array with three Employee objects
Employee[] staff = new Employee[3];
staff[0]=new Employee("Carl Cracker",75000,1987,12,15);
staff[1]=new Employee("Harry Hacker",50000,1989,10,1);
staff[2]=new Employee("Tony Tester",40000,1990,3,15);
// raise everyone's salary by 5%
for(Employee e : staff)
e.raiseSalary(5);
// print out information about all Employee objects
for(Employee e : staff)
System.out.println("name"+e.getName()+",salary="+e.getSalary()+",hireday="+e.getHireDay());
}
}
class Employee{
private String name;
private double salary;
private LocalDate hireDay;
public Employee(String n,double s,int year,int month,int day){
name = n;
salary = s;
hireDay = LocalDate.of(year,month,day);
}
public String getName(){
return name;
}
public double getSalary(){
return salary;
}
public LocalDate getHireDay(){
return hireDay;
}
public void raiseSalary(double byPercent){
double raise = salary * byPercent /100;
salary += raise;
}
}

类通常包括类型属于某个类类型的实例域,一个方法可以访问所属类的所有对象的私有数据.
在下面俩种情况下使用静态方法:
一个方法不需要访问对象状态,其所需要参数都是通过显示参数提供(例如: Math.pow)
一个方法只需要访问类的静态域(例如: Employee.getNextId);

如果多个方法有相同的名字不同的参数,便产生了重载.Java允许重载任何方法,而不只是构造器方法.要完整描述一个,需要指出方法名和参数类型.这叫做方法的签名.必须明确地初始化方法中的局部变量,但是如果没有初始化类中域,将会自动化初始化为默认值.

下面程序4-5中的程序展示了本节讨论的很多特性:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
import java.util.*;
public class ConstructorTest{
public static void main(String args){
// fill the staff array with three Employee objects
Employee[] staff = new Employee[3];
staff[0] = new Employee(6000);
staff[1] = new Employee("Harry",40000);
staff[2] = new Employee();
// print out infomation about all Employee objects
for(Employee e : staff)
System.out.println("name="+e.getName()+".id="+e.getId()+",salary="+e.getSalary());
}
}
class Employee
{
private static int nextId;
private int id;
private String name = ""; // instance field initialization
private double salary;
// static initialization block
static
{
Random generator = new Random();
// set nextId to a random number between 0 and 999
nextId = generator.nextId(1000);
}
// object initialization block
{
id = nextId;
nextId++;
}
// three overloaded constructors
public Employee(String n, double s){
name = n;
salary = s;
}
public Employee(double s){
// calls the Employee(String, double) constructor
this("Employee #"+nextId,s);
}
// the default constructor
public Employee(){
// name initialized to "" -- see above
// salary not explictly set --initialized to 0
// id initialized in initialization block
}
public String getName(){
return name;
}
public double getSalary(){
return salary;
}
public int getId(){
return id;
}
}

可以为任何一个类添加finalize方法,finalize方法方法回收短缺的资源,在垃圾回收清除对象之前调用.如果某个资源需要在使用完毕之后立刻关闭,那么就需要由人工来管理.对象用完时,可以使用一个close方法来完成相应的清理操作.

Java允许使用包(package)将类组织起来,借助于包可以方便地组织自己的代码,并将自己的代码与别人提供的代码库分开管理.标准的Java类库分布在多个包中,包括Java.lang java.util java.net等.

类设计技巧: 应用这些技巧可以使得设计出来的类更具有oop专业水准.

1 一定要保证数据私有
2 一定要对数据初始化
3 不要在类中使用过多的基本类:用其他的类代替多个相关的基本类型的使用.
4 不是所有的域都需要独立的域访问器和域更改器.
5 将职责过多的类进行分解
6 类名和方法名要能够体现他们的职责:命名类名的良好习惯是采用一个名词(Order) 前面有形容词修饰的名词(RushOrder) 或动名词(有"ing"后缀)修饰名词(BillingAddress).对于方法来说,习惯是访问器方法用小写get开头,更改器方法用小写set开头.
7 优先使用不可变的类

继承

类 超类 子类         参数数量可变的方法
Object:所有类的超类   枚举类
泛型数组列表          反射
对象包装器与自动装箱   继承的设计技巧

“is-a”规则的另一种表述法是置换法则,它表明程序中出现超类对象的任何地方都可以用子类对象置换.

对象包装器与自动装箱

所有的基本类型都有一个与之对应的类,这些类称为包装器.这些对象包装器类拥有很明显的名字:Integer Long Float Double Short Byte Character Void Boolean(前6个类派生于公共的超类Number).对象包装器类是不可变的,一旦构造了包装器,就不允许更改包装器在其中的值.同时,对象包装器还是final,不能定义他们的子类.

继承的设计技巧

1 将公共操作和域放在超类
2 不要使用受保护的域
3 使用继承实现"is-a"关系
4 除非所有继承的方法都有意义,否则不要使用继承
5 在覆盖方法时,不要改变预期的行为
6 使用多态,而非类型信息
7 不要过多的使用反射(反射机制使得人们可以通过在运行时查看域和方法,让人们编写出更具有通用性的程序,这种功能对于编写系统程序来说极其实用,但是通常不适于编写应用程序.反射是很脆弱的,即编译器很难帮助人们发现程序中的错误,因此只有在运行时才会发现错误并导致异常)

反射 编写动态操纵Java代码的程序.
反射库(reflection library)提供了一个非常丰富且精心设计的工具集,以便编写能够动态操纵Java代码的程序.它是Java组件的体系结构.特别是在设计或运行中添加新类时,能够快速的应用开发工具动态的查询新添加类的能力.

能够分析类能力的程序称为反射(reflective).反射机制的功能极其强大.

反射机制可以用来:
在运行时分析类的能力
在运行时查看对象,比如编写一个toString方法供所有类使用.
实现通用的数组操作代码
利用Method对象,这个对象很像C++中的函数指针

反射是一种功能强大且复杂的机制,使用它的主要人员是工具构造者,而不是应用程序员.

Class类
在程序运行期间,Java运行时系统始终为所有的对象维护一个被称为运行时的类型标识.这个信息跟踪着每个对象所属的类,虚拟机利用运行时类型信息选择相应的方法执行.保存这些信息的类被称为Class,Object类中的getClass()方法将会返回一个Class类型的实例.

在java.lang.reflect包中有三个类Field Method 和 Constructor分别用于描述类的域 方法和构造器.这三个类都有一个叫做getName的方法,用来返回项目的名称
接口 lambda表达式与内部类

接口               内部类
接口示例             代理
lambada表达式

在Java程序设计中,接口不是类,而是对类的一组需求描述,这些类需要遵从接口描述的统一格式进行定义.
例子: Arrays类中的sort方法承诺可以对对象数组进行排序,但要求满足下列前提:对象所属的类必须实现了Comparable接口.下面是Comparable接口的代码

1
2
3
4
5
6
7
8
9
10
11
// 任何实现Comparable接口的类都需要包含compareTo方法,并且这个方法的参数必须是一个Object对象,返回一个整型数值.
// 接口中的所有方法自动属于public,在接口声明中不用提供关键字public
public interface Comparable{
int compareTo(Object other);
}
// Java SE 5.0中,Comparable接口已经改进为泛型类型
public interface Comparable<T>{
int compareTo(T other);
}
//接口中还可以定义常量,重要的是知道接口不能提供哪些功能,接口绝对不能有实例域.接口没有实例,Java SE8 可以在接口中提供简单的方法,但是不能引用实例域.

提供实例域和方法实现的任务应该由实现接口的那个类来完成.为了让类实现一个接口,通常需要下面俩个步骤:
1 将类声明为实现给定的接口
2 对接口中的所有方法进行定义
要将类声明为实现某个接口,需要使用关键字implenments:class Employee implements Comparable , 以下是compareTo方法的实现:

1
2
3
4
5
//实现接口时,必须把方法声明为public,否则编译器将认为这个方法的访问属性为包可见性,即类的默认访问属性.
public int compareTo(Object otherObject){
Employee other = (Employee) otherObject;
return Double.compare(salary,other.salary);
}

回调是一种常见的程序设计模式,在这种模式中,可以指出某个特定事件发生时应该采取的动作.
在标准类库中采用的是面向对象方法,它将某个类的对象传递给定时器,然后,定时器调用这个对象的方法,由于对象可以携带一些附加的信息,所以传递一个对象比传递一个函数灵活得多.
定时器需要知道调用哪一个方法,并要求传递的对象所属所属的类实现了java.awt.event包中ActionListener接口,下面是这个接口:

1
2
3
4
public interface ActionListener
{
void actionPerformed(ActionEvent event)
}

假设希望每隔10秒打印一条信息,”At the one,the time is …”,然后响一声,就应该定义一个实现ActionListener接口的类,然后将需要执行的语句放在actionPerformed方法中.

1
2
3
4
5
6
class TimePrinter implements ActionListener{
public void actionPerformed(ActionEvent event){
System.out.println("At the one, the time is "+ new Date());
Toolkit.getDefaultToolkit().beep();
}
}

接下来,构造这个类的第一个对象,并将它传递给Timer构造器

1
2
ActionListener listener = new TimePrinter();
Timer t =new Timer(1000,listener)

最好,启动定时器

1
t.start()

lambda表达式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package lambda;
import java.util;
import javax.swing.*;
import javax.swing.Timer;
public class lambdaTest
{
public static void main(String[] args){
String[] planets = new String[] {"Mercury","Venus","Earth","Mars","Jupiter","Saturn","Urans","Neptune"};
System.out.prinln(Arrays.toString(planets));
System.out.ptinln("Sorted in dictionary order:");
Arrays.sort(planets);
System.out.printlnn(Arrays.toString(planets));
System.out.println("Sorted by length:");
Arrays.sort(planets,(first,second)->first.length()-second.length());
System.out.println(Arrays.toString(planets));
Timer t = new Timer(1000,event->System.out.println("The time is"+new Date()));
t.start();
JOptionPane.showMessageDialog(null,"Quit program?");
System.exit(0);
}
}

最好把lambda表达式看作是一个函数,而不是一个对象,另外要接受lambda表达式可以传递到函数式接口.

内部类
内部类(inner Class)是定义在另一个类中的类.使用内部类的主要原因有三点:

内部类方法可以访问该类定义所在作用域中的数据,包括私有数据.
内部类可以对同一个包中的其他类隐藏起来
当想要定义一个回调函数且不想编写大量代码时,使用匿名内部类比较便捷.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 俩个参数: 发布通告和开关铃声的标志
// TimerPrinter 对象是由TalkingClock类的方法构造
public class TalkingClock{
private int interval;
private boolean beep;
public TalkingClock(int interval,boolean beep){...}
public void start(){...}
public class TimePrinter implements ActionListener{
public void actionPerformed(ActionEvent event){
System.out.println("At the tone,the time is" + new Date());
if (beep) Toolkit.getDefaultToolkit().beep();
}
}
}
// 内部类既可以访问自身的数据域,也可以访问创建它的外围类对象的数据域.\

只有内部类可以是私有类,而常规类只可以具有包可见性,或公有可见性.

前6章代理和反射看的比较费劲

异常 断言和日志

处理错误            使用断言
捕获异常            记录日志
使用异常机制的技巧    调试技巧

在Java程序设计中,异常对象都是派生于Throwable类的一个实例.所有的异常都是由Throwable继承而来的,但是下一层立即分解为俩个分支:Error和Exception

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package pair3;
public class Pair<T>
{
private T first;
private T second;
public Pair() { first = null; second = null }
public Pair(T first, T second){ this.first = first; this.second = second }
public T getFirst() { return first; }
public T getSecond() { return second; }
public void setFrist(T newValue) { first = newValue; }
public void setSecond(T newValue) { second = newValue; }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package pair3;
import java.time.*;
public class Employee
{
private String name;
private double salary;
private LocalDate hireDay;
public Employee(String name, double salary, int year, int month, int day)
{
this.name = name;
this.salary = salary;
hireDay = LocalDate.of(year, month, day);
}
public String getName(){
return name;
}
public double getSalary(){
return salary;
}
public LocalDate getHireDay(){
return hireDay;
}
public void raiseSalary(double byPercent){
double raise = salary * byPercent / 100;
salary += raise;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package pair3;
public class Manager extends Employee
{
private double bonus;
public Manager(String name,double salary, int year, int month, int day){
super(name,salary,year,month,day);
bonus = 0;
}
public double getSalary(){
double baseSalary = super.getSalary();
return baseSalary + bonus;
}
public void setBonus(double b){
bonus = b;
}
public double getBonus(){
return bonus;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
package pair3;
public class PairTest3{
public static void main(String[] args){
Manager ceo = new Manager("Gus Greedy",800000,2003,12,15);
Manager cfo = new Manager("Sid Sneaky", 600000,2003,12,15);
Pair<Manager> buddies = new Pair<>(ceo, cfo);
printBuddies(buddies);
ceo.setBonus(1000000);
cfo.setBonus(500000);
Manager[] mangers = { ceo, cfo};
Pair<Employee> result = new Pair<>();
minmaxBonus(managers, result);
System.out.println("first: "+ result.getFirst().getName() + ",second: "+ result.getSecond().getName());
maxminBonus(managers,result);
System.out.prinln("first:" + result.getFirst().getName()+",second:"+result.getSecond().getName());
}
public static void printBuddies(Pair<? extends Employee> p){
// 子类限定可以读取对象
Employee first = p.getFirst();
Employee second = p.getSecond();
System.out.println(first.getName() + " add " + second.getName() + " are buddies. ");
}
public static void minmaxBonus(Manger[] a,Pair<? super Manager> result){
// 父类限定可以设置对象
if (a.length == 0) return;
Manager min = a[0];
Manager max = a[0];
for (int i=0; i< a.length; i++){
if(min.getBonus() > a[i].getBonus()) min = a[i];
if(max.getBonus()<a[i].getBonus()) max = a[i];
}
result.setFirst(min);
result.setSecond(max);
}
public static void maxminBonus(Manager[] a, Pair<? super Manager> result)
{
minmaxBonus(a,result);
PairAlg.swapHelper(result);
}
}
class PairAlg
{
public static boolean hasNulls(Pair<?> p){
return p.getFirst() == null || p.getSecond() == null;
}
public static void swap(Pair<?> p) { swapHelper(P); }
public static <T> void swapHelper(Pair<T> p){
T t=p.getFirst();
p.setFirst(p.getSecond());
p.setSecond(t);
}
}

集合

Java集合框架        视图与包装器
具体的集合           算法
映射                遗留的集合

容器和组件是”组合(composite)”模式
带滚动条的面板是”装饰器(decorator)”模式
布局管理器是”策略(strategy)”墨菲
闭包是一个可调用的对象,它记录了一些信息,这些信息来自于创建它的作用域

Recommended Posts