Java要点和《疯狂Java讲义》例程整理

基础知识

imoprt

The import keyword is to bring in an entire library or a member of that one 
import java.util.*;
import java.util.Vector;
import static java.lang.Math.*;

compilation unit

Each compilation unit must have a name ending in java, and inside the compilation unit there can be a public class that must have the same name as teh file. There can be only one public class in each compilation unit.

classpath

Place all the .class files for a particular package into a single directory
CLASSPATH contains one or more directories that are used as roots for a search for .class files.


流程控制

public class Test{
	
	public static void main(String[] args)
	{
		int n = 0, m, j, i;
		for(i=3; i<=100; i+=2)
		{
			if(i>=20)
			{
				i=100;
				continue;
			}
			m = (int)Math.sqrt((double)i);
			for(j=2; j<=m; j++)
			{
				if((i%j) == 0)
					break;
			}
			if(j > m)
			{
				System.out.print(i+"\t");
				n++;
				if(n%5 == 0)
					System.out.println();
			}
		}
	}
}

3	5	7	11	13	
17	19

带标签的break

P83
public class Test {
	public static void main(String[] args){
		outer:
		for(int i=0; i<5; ++i){
			for(int j=0; j<3; ++j){
				System.out.println("i : "+i+", j : "+j);
				if( j == 1 ){
					break outer;
				}
			}
		}
	}
}

i : 0, j : 0
i : 0, j : 1

带标签的continue

P85
public class Test {
	public static void main(String[] args){
		outer:
		for(int i=0; i<5; ++i){
			for(int j=0; j<3; ++j){
				System.out.println("i : "+i+", j : "+j);
				if( j == 1 ){
					continue outer;
				}
			}
		}
	}
}

i : 0, j : 0
i : 0, j : 1
i : 1, j : 0
i : 1, j : 1
i : 2, j : 0
i : 2, j : 1
i : 3, j : 0
i : 3, j : 1
i : 4, j : 0
i : 4, j : 1

类绑定

public class Test {
	public static void main(String[] args){
		A a = new B();
		a.f(a);
	}
}

class A{
	public void f(A x){
		System.out.println("A.f(A)");
	}
	public void f(B x){
		System.out.println("A.f(B)");
	}
}

class B extends A{
	public void f(A x){
		System.out.println("B.f(A)");
	}
	public void f(B x){
		System.out.println("B.f(B)");
	}
}

B.f(A)

类的初始化

P159
public class Test {
	public static void main(String[] args){
		new Leaf();
		new Leaf();
	}
}

class Root
{
	static{
		System.out.println("Root's static init block");
	}
	{
		System.out.println("Root's normal init block");
	}
	public Root()
	{
		System.out.println("Root's Non-arg Ctor");
	}
}

class Mid extends Root
{
	static{
		System.out.println("Mid's static init block");
	}
	{
		System.out.println("Mid's normal init block");
	}
	public Mid()
	{
		System.out.println("Mid's Non-arg Ctor");
	}	
}

class Leaf extends Mid
{
	static{
		System.out.println("Leaf's static init block");
	}
	{
		System.out.println("Leaf's normal init block");
	}
	public Leaf()
	{
		System.out.println("Leaf's Non-arg Ctor");
	}	
}

Root's static init block
Mid's static init block
Leaf's static init block
Root's normal init block
Root's Non-arg Ctor
Mid's normal init block
Mid's Non-arg Ctor
Leaf's normal init block
Leaf's Non-arg Ctor
Root's normal init block
Root's Non-arg Ctor
Mid's normal init block
Mid's Non-arg Ctor
Leaf's normal init block
Leaf's Non-arg Ctor

基本数据类型的包装类

P166
public class Test {
	public static void main(String[] args){
		Integer ina = 2;
		Integer inb = 2;
		System.out.println(ina == inb);
		Integer biga = 128;
		Integer bigb = 128;
		System.out.println(biga == bigb);
	}
}

true
false

== 和 equals方法

当使用== 来判断两个变量是否相等时,如果都是基本变量类型,且都是数值类型,则只要值相等,就返回true;对于两个引用类型变量,必须指向同一个对象,==判断才为true;对于基本数据的包装类,值相等则判断为true
equals是Object类提供的实例方法,可以重写equals方法实现对象的自定义比较。

P169
public class Test {
	public static void main(String[] args){
		int it = 65;
		float fl = 65.0f;
		System.out.println(it == fl);
		char ch = 'A';
		System.out.println(it == ch);
	}
}

true
true

P169
public class Test {
	public static void main(String[] args){
		String s1 = "abcd";
		String s2 = "ab";
		String s3 = "cd";
		String s4 = "ab" + "cd";
		String s5 = "a" + "b" + "cd";
		String s6 = s2 + s3;
		String s7 = new String("abcd");
		System.out.println(s1 == s4);
		System.out.println(s1 == s5);
		System.out.println(s1 == s6);
		System.out.println(s1.equals(s6));
		System.out.println(s1 == s7);
		System.out.println(s1.equals(s7));
	}
}

true
true
false
true
false
true

静态类方法

P173
	public static void NullAccessStaticTest(){
		System.out.println("NullAccessStaticTest");
	}
	
	public static void main(String[] args){
		Test test = null;
		test.NullAccessStaticTest();
	}

NullAccessStaticTest

单例类

P174
class Singleton {
	private static Singleton instance;
	private Singleton(){}
	public static Singleton getInstance()
	{
		if(instance == null){
			instance = new Singleton();
		}
		return instance;
	}
}

public class Test {
	
	public static void main(String[] args){
		Singleton s1 = Singleton.getInstance();
		Singleton s2 = Singleton.getInstance();
		System.out.println(s1 == s2);
	}
}

true

final

final修饰的对象只能被赋值一次
在编译时能够确定的值称为“宏变量”,需要调用函数等的则不是
P178
public class Test {
	public static void main(String[] args){
		final String book = "abcd" + 99.0;
		final String book2 = "abcd" + String.valueOf(99.0);
		System.out.println(book == "abcd99.0");
		System.out.println(book2 == "abcd99.0");
	}
}

true
false

抽象类和接口

  • 接口只能包含抽象方法;抽象类可以 包含普通方法
  • 接口不能定义静态方法;抽象类可以
  • 接口只能定义静态常量Field,不能定义普通Field;抽象类都可以
  • 接口里不包含构造器;抽象类可以包含
  • 接口里不能包含初始化块;抽象类可以
  • 一个类最多只能有一个直接父类;但一个类可以直接实现多个接口

内部类

非静态内部类中,内部类访问外部类属性,外部类访问内部类属性
P202
public class Outer {
	private String outProp = "outProp";
	
	private class Inner{
		private String inProp = "inProp";
		private void accessOuterProp()
		{
			System.out.println(outProp);
		}
	}
	
	public void accessInnerProp(){
		Inner in = new Inner();
		in.accessOuterProp();
		System.out.println(in.inProp);
	}
	
	public static void main(String[] args){
		Outer out = new Outer();
		out.accessInnerProp();
		Inner in = new Outer().new Inner();
		in.accessOuterProp();
	}
}

outProp
inProp
outProp

外部类访问静态内部类的静态变量和普通成员变量
P204
public class Outer {
	static class Inner{
		private static int prop1 = 5;
		private int prop2 = 9;
	}
	
	public void accessInnerProp(){
		System.out.println(Inner.prop1);
		System.out.println(new Inner().prop2);
	}
	
	public static void main(String[] args){
		Outer out = new Outer();
		out.accessInnerProp();
	}
}

5
9

在外部类以外创建非静态内部类实例
P205
public class Test {
	public static void main(String[] args){
		Out.In in = new Out().new In("Test Message");
	}
}

class Out
{
	class In
	{
		public In(String msg)
		{
			System.out.println(msg);
		}
	}
}

Test Message

外部类以外继承内部类
P206
public class Test {
	public static void main(String[] args){
		new Subclass(new Out());
	}
}

class Subclass extends Out.In
{
	public Subclass(Out out)
	{
		out.super("hello");
	}
}

class Out
{
	class In
	{
		public In(String msg)
		{
			System.out.println(msg);
		}
	}
}

hello

在外部类之外使用静态内部类
P207
public class Test {
	public static void main(String[] args){
		StaticOut.StaticIn in = new StaticOut.StaticIn();
	}
}

class StaticOut
{
	static class StaticIn
	{
		public StaticIn(){
			System.out.println("Ctor of StaticIn");
		}
	}
}

Ctor of StaticIn

匿名内部类

构造格式如下
new 父类构造函数(实参列表) | 实现接口()
{
        //匿名内部类的类体部分
}

枚举类

  • 枚举类可以实现接口,使用enum定义的枚举类继承了java.lang.Enum类,而不是Object类,并且实现了java.lang.Serializable和lava.lang.Comparable两个接口
  • 使用enum定义、非抽象的枚举类默认会使用final修饰,因此不能派生子类
  • 枚举类的构造器只能使用private访问控制符
  • 枚举类的所有实例必须在枚举类的第一行显示列出,且系统会自动添加public static final修饰符
使用示例
P215
public class Test {
	public void judge(SeasonEnum e){
		switch (e) {
		case SPRING:
			System.out.println("Spring");
			break;
		case SUMMER:
			System.out.println("Summer");
		case FALL:
			System.out.println("Fall");
		case WINTER:
			System.out.println("Winter");
		default:
			break;
		}
	}
	public static void main(String[] args){
		for(SeasonEnum s:SeasonEnum.values())
		{
			System.out.println(s);
		}
		new Test().judge(SeasonEnum.SPRING);
	}
}

enum SeasonEnum
{
	SPRING, SUMMER, FALL, WINTER;
}

SPRING
SUMMER
FALL
WINTER
Spring

枚举类的Field,方法和构造器

最科学合理的使用方法
P218
public class Test {
	public static void main(String[] args){
		Gender gender = Enum.valueOf(Gender.class, "FEMALE");
		System.out.println(gender.getName());
	}
}

enum Gender{
	MALE("男"), FEMALE("女");
	private final String name;
	private Gender(String name){
		this.name = name;
	}
	public String getName()
	{
		return this.name;
	}
}


包含接口和抽象方法的枚举类

P219,P220
public enum Operation implements Info{
	PLUS
	{
		public double eval(double x, double y)
		{
			return x+y;
		}
		
		public void info()
		{
			System.out.println("Plus");
		}
	},
	MINUS
	{
		public double eval(double x, double y)
		{
			return x-y;
		}
		
		public void info()
		{
			System.out.println("Minus");
		}
	},
	TIMES
	{
		public double eval(double x, double y)
		{
			return x*y;
		}
		
		public void info()
		{
			System.out.println("Times");
		}
	},
	DIVIDE
	{
		public double eval(double x, double y)
		{
			return x / y;
		}
		
		public void info()
		{
			System.out.println("Divide");
		}
	};
	
	public abstract double eval(double x, double y);
	
	public static void main(String[] args) {
		System.out.println(Operation.PLUS.eval(3, 4));
		System.out.println(Operation.MINUS.eval(3, 4));
		System.out.println(Operation.TIMES.eval(3, 4));
		System.out.println(Operation.DIVIDE.eval(3, 4));
	}

}

interface Info{
	void info();
}

7.0
-1.0
12.0
0.75

Set

Set实现了Collection接口。Set不允许包含重复元素,集合多个对象之间没有明显的顺序。Set的实现有
  1. HashSet  添加进HashSet的Object必须实现了hashCode()方法。元素之间用equals()方法比较是否相同。它有一个子类 LinkedHashSet,用hashCode()决定元素的储存位置,并将元素按插入顺序连接起来。
  2. TreeSet  可以确保集合中元素处于排序状态。

List

List实现了Collection接口。List代表一个元素有序,可重复的集合,集合中每个元素都有其对应的顺序索引。List允许包含重复元素,可以通过索引来访问指定位置的元素。List的实现有
  1. ArrayList 
  2. LinkedList
使用 Arrays.asList()方法可以生成一个固定长度的List

Map

Map用于保存具有映射关系的数据,因此Map保存着两组值,key和value。key和value存在单向一对一关系

使用泛型

List<String> strList = new ArrayList<String>();
Map<String, Integer> scores = new HashMap<String, Integer>();
// After Java 7
List<String> strList = new ArrayList<>();
Map<String, Integer> scores = new HashMap<>();

Iterator

import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;

public class Test {
	public static void main(String[] args){
		List<String> strList = new LinkedList<String>();
		strList.add("a");
		strList.add("b");
		strList.add("c");
		strList.add("d");
		Iterator it = strList.iterator();
		while(it.hasNext())
		{
			String str = (String)it.next();
			System.out.println(str);
			if(str.equals("c")){
				it.remove();
			}
			str = "test";
		}
		System.out.println(strList);
	}
}

a
b
c
d
[a, b, d]

泛型声明

P296
public class Test {
	public static void main(String[] args){
		Apple<String> a1 = new Apple<String>("apple");
		System.out.println(a1.getInfo());
		
		Apple<Double> a2 = new Apple<Double>(3.14);
		System.out.println(a2.getInfo());
	}
}

class Apple<T>
{
	private T info;

	public Apple(){}
	
	public Apple(T info)
	{
		this.info = info;
	}
	
	public void setInfo(T info)
	{
		this.info = info;
	}
	
	public T getInfo()
	{
		return this.info;
	}
}

apple
3.14

从泛型类派生子类

P297
public class Test {
	public static void main(String[] args){
		A1 a1 = new A1();
		a1.setInfo("hello");
		System.out.println(a1.getInfo());
		A2 a2 = new A2();
		a2.setInfo(123);
		System.out.println(a2.getInfo());
	}
}

class Apple<T>
{
	private T info;

	public Apple(){}
	
	public Apple(T info)
	{
		this.info = info;
	}
	
	public void setInfo(T info)
	{
		this.info = info;
	}
	
	public T getInfo()
	{
		return this.info;
	}
}

class A1 extends Apple<String>
{
	public String getInfo()
	{
		return "SubClass" + super.getInfo();
	}
}

class A2 extends Apple
{
	public String getInfo()
	{
		return super.getInfo().toString();
	}
}

SubClasshello
123

P298
import java.util.ArrayList;
import java.util.List;

public class Test {
	public static void main(String[] args){
		List<String> l1 = new ArrayList<String>();
		List<Integer> l2 = new ArrayList<Integer>();
		System.out.println(l1.getClass() == l2.getClass());
                System.out.println(l1 instanceof ArrayList);
	}
}

true
true

由于系统中不会真正生成泛型类,所以 instanceof 运算符后不能使用泛型类

类型通配符

P300
import java.util.Arrays;
import java.util.List;

public class Test {
	public void test(List<?> c)
	{
		for(int i=0; i<c.size(); ++i)
		{
			System.out.println(c.get(i));
			// System.out.println(c.get(i).getClass());
		}
	}
	public static void main(String[] args){
		new Test().test(Arrays.asList("abcd", 1, 1.23, 'A'));
	}
}

abcd
1
1.23
A

P302
import java.util.List;
import java.util.Arrays;

public class Canvas {
	public void drawAll(List<? extends Shape> shapes)
	{
		for(Shape s : shapes){
			s.draw(this);
		}
	}

	public String toString()
	{
		return "Canvas";
	}
	
	public static void main(String[] args)
	{
		List<Circle> circleList = Arrays.asList(new Circle(), new Circle());
		Canvas c = new Canvas();
		c.drawAll(circleList);
	}
}

abstract class Shape
{
	public abstract void draw(Canvas c);
}

class Circle extends Shape
{
	public void draw(Canvas c)
	{
		System.out.println("Draw a circle on " + c);
	}
}

Draw a circle on Canvas
Draw a circle on Canvas

甚至可以为类型参数设定多个上限
public class Apple<T extends Number & java.io.Serializable>
{
	...
}

也可以设置通配符/泛型的下限
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

public class Test {
	
	public static<T>  T copy(Collection<? super T> dest, Collection<T> src)
	{
		T last = null;
		for (T ele : src){
			last = ele;
			dest.add(ele);
		}
		return last;
	}
	
	public static void main(String[] args){
		List<Number> ln = new ArrayList<Number>();
		List<Integer> li = new ArrayList<Integer>();
		li.add(5);
		Integer last = copy(ln, li);
		System.out.println(last);
	}
}

5

泛型和数组不能同时使用,比如下面语句就会报错
List<String>[] lsa = new ArrayList<String>[10];

异常处理

  • Java把所有非正常情况分成两种 Exception 和 Error, 都继承自 Throwable父类
  • try块后最多只有一个catch块会被执行
  • try块后的花括号不能省略
  • 所有父类异常的catch都必须在子类异常catch后面
  • 不管try块中代码是否异常,finally块中代码总会被执行,所以可以用来回收try块中打开的物理资源
  • 子类方法中抛出的异常应该是父类方法声明抛出异常的子类或相同,子类方法中不允许抛出比父类方法声明更多的异常。

throws用法

import java.io.FileInputStream;
import java.io.IOException;

public class Test {
	public static void test() throws IOException
	{
		FileInputStream fils = new FileInputStream("a.txt");
	}
	public static void main(String[] args)
	{
		try{
			test();
		}
		catch(IOException e)
		{
			System.out.println("catch the exception");
		}
	}
}

throw 用法

import java.io.FileInputStream;
import java.io.IOException;

public class Test {
	public static void test() throws IOException
	{
		throw new IOException("haha");
	}
	public static void main(String[] args)
	{
		try{
			test();
		}
		catch(IOException e)
		{
			System.out.println(e.getMessage());
		}
	}
}

haha

自定义异常类

public class AuctionException extends Exception
{
	public AuctionException(){}
	
	public AuctionException(String msg)
	{
		super(msg);
	}
}

Throw All

try
{
...
}
catch (Throwable t)
{
...
}

练习

import java.io.IOException;

import javax.swing.JFrame;

public class Test {
	public static void main(String[] args)
	{
		int i;
		for(i=0; i<3; i++)
		{
			try{
				System.out.println("i="+i);
				throw new MyException();
			}
			catch(MyException e)
			{
				System.out.println(e.Say());
			}
		}
	}
}

class MyException extends Exception
{
	static int intNumber = 0;
	MyException()
	{
		intNumber++;
	}
	String Say()
	{
		return "No"+intNumber+":MyException!";
	}
}

i=0
No1:MyException!
i=1
No2:MyException!
i=2
No3:MyException!


IO

FIle类

代表与平台无关的文件和目录,能操作文件和目录,但是不能访问文件本身。

IO流

字节流和字符流
字节流最小数据单元是8位的字节,字符流是16位的字符
字节流主要由InputStream, OutputStream作为基类,字符流主要由Reader和Writer作为基类,他们都是抽象类

对象序列化

P678,679
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

public class Test {
	public static void main(String[] args) throws Exception
	{
		try{
			ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("object.txt"));
			Person per = new Person("Tom", 13);
			oos.writeObject(per);
			oos.close();
		}
		catch(IOException e)
		{
			e.printStackTrace();
		}
		
		try{
			ObjectInputStream ois = new ObjectInputStream(new FileInputStream("Object.txt"));
			Person p = (Person)ois.readObject();
			System.out.println("name:"+p.name+",age:"+p.age);
			ois.close();
		}
		catch(Exception e)
		{
			e.printStackTrace();
		}
	}
}

class Person implements Serializable
{
	public String name;
	public int age;
	
	public Person(String name, int age)
	{
		this.name = name;
		this.age = age;
	}
}

name:Tom,age:13

GUI

组件、容器、布局管理器的关系

组件Component代表一个能以图形化方式显示出来,并且可以和用户交互的对象
  • 容器Container是一种特殊的组件,是可以盛装组件的组件
  • 布局管理器是容器管理它里面组件布局的方式

Panel

  • AWT中典型的容器,可作为容器来盛装其他组件,为放置提供空间
  • 不能单独存在,必须放置到其他容器中
  • 默认使用FLowLayout作为其布局管理器

Frame

  • Frame代表常见的窗口,是Window类的子类
  • Frame对象有标题,允许通过拖拉来改变窗口的位置,大小
  • 初始化时不可见,可用setVisible(true)使其显示出来
  • 默认使用BorderLayout作为其布局管理器
import java.awt.*;

public class Test extends java.applet.Applet{
	Choice testChoice;
	List testList;
	public void init()
	{
		testChoice = new Choice();
		testList = new List();
		for(int i=1; i<=3; i++){
			testChoice.addItem(String.valueOf(i));
			testList.addItem("Item "+i);
		}
		setLayout(new FlowLayout());
		add(testChoice);
		add(testList);
	}
	
	public static void main(String[] args)
	{
		new Test();
	}
}


布局管理器

每个容器都有默认的布局管理器,也可以通过如下代码设置
c.setLayout(new XXXLayout());
Window容器可以通过pack()方法把窗口调整到最佳大小

AWT提供了FlowLayout, BorderLayout, GridLayout, GridBagLayout, CardLayout 五种布局,Swing还提供了BoxLayout
  • FlowLayout中,组件像水流一样向某方向流动(排列),遇到边界就另起一行重新开始拍列
  • BorderLayout将容器分为EAST,SOUTH,WEST,NORTH,CENTER五个位置,普通组件被放在五个位置中的任一位置,因此BorderLayout最多只能放5个组件,向同一位置添加多个组件时,后添加的覆盖先添加的。
  • GridLayout将容器分割成纵横线分隔的网格,每个网格占的大小相同,默认从左到右,从上到下添加组件
  • GridBagLayout类似GridLayout,但是一个组件可以跨越多个网格,使用GridBagLayoutConstraint控制
  • CardLayout以时间而非空间来管理它里面的组件,它将加入容器的所有组件看成一叠卡片,每次只有最上面的容器才可见。
  • 绝对定位,首先调用容器方法setLayout(null),然后向容器添加组件时,先调用setBounds()或setSize(),再将组件添加到容器中。
  • BoxLayout可以在垂直和水平两个方向上摆放组件,保留了GridBagLayout的很多优点,但是没有那么复杂
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

public class Test extends JApplet implements ActionListener{
	JButton bt1 = new JButton("North");
	JButton bt2 = new JButton("West");
	JButton bt3 = new JButton("East");
	JButton bt4 = new JButton("South");
	JLabel lb1 = new JLabel("Center");
	Container cp = getContentPane();
	
	public void init()
	{
		cp.setLayout(new BorderLayout());
		cp.add("North", bt1);
		cp.add("West", bt2);
		bt2.addActionListener(this);
		cp.add("East", bt3);
		cp.add("South", bt4);
		bt4.addActionListener(this);
		cp.add("Center", lb1);
	}
	
	public void actionPerformed(ActionEvent e)
	{
		lb1.setText("Please Press a Button");
		if(e.getSource() == bt2)
			lb1.setText("Press West");
		if(e.getSource() == bt4)
			lb1.setText("Press South");
	}
}


AWT基本组件有

P386
  • Button
  • Canvas
  • Checkbox
  • CheckboxGroup
  • Choice
  • Frame
  • Label
  • List
  • Panel
  • Scrollbar
  • ScrollPane
  • TextArea
  • TextField
 

Java事件模型的流程

  • Event Source:事件发生的场所,通常是各个组件,例如按钮,窗口,菜单等
  • Event:封装了GUI组件上发生的特定事情(通常是一次用户操作),程序员要获得GUI组件上所发生事件的相关信息,都通过Event对象来取得。
  • EventListener:负责监听事件源所发生的的事件,并对其作出响应处理

AWT菜单

  • MenuBar:菜单条,菜单的容器
  • Menu:菜单项的容器,也可以作为菜单项使用
  • PopupMenu:上下文菜单组件
  • MenuItem:菜单项组件
  • CheckboxMenuItem:复选框菜单项组件
  • MenuShortcut:菜单快捷键组件

画图

Component类里提供了和绘图有关的三个方法
  • paint(Graphics g):绘制组件的外观
  • update(Graphics g):调用paint()方法,刷新组件外观
  • repaint():调用update()方法,刷新组件外观

Graphics类

Graphics是一个抽象的画笔对象,可以在组件上绘制丰富多彩的几何图形和位图。

Swing

Swing是一种轻量级组件,100%java实现,不再依赖本地平台的图形界面,对跨平台的支持更加出色。
Swing提供了比AWT更多的的图形界面组件
Swing组件都采用了MVC(Modle-View-Controller)的设计模式,可以实现GUI组件的显示逻辑和数据逻辑的分离,提供更多的灵活性。
大部分Swing组件都是JComponent抽象类的子类,JComponent类是AWT里Container类的子类,所以Swing组件都可以作为容器使用。
Swing为除了Canvas之外的所有AWT组件提供了相应的实现
很多Swing组件可以使用图标修饰自己
支持插拔式的的外观风格。每个JComponent对象都有一个相应的ComponentUI对象,为它完成所有的绘画,事件处理,决定尺寸大小等工作。
支持设置边框

JFrame

A Frame is a top-level window with a title and a border
A fraem, implemented as an instance of the JFrame class, is a window that typically has decorations such as a border, a title and buttons for closing and iconifying the window.
它的setDefaultCloseOperation操作可设置用户发起“close”时的默认操作,选项有
  • DO_NOTHING_ON_CLOSE
  • HIDE_ON_CLOSE
  • DISPOSE_ON_CLOSE
  • EXIT_ON_CLOSE
默认情况下,被设置为 HIDE_ON_CLOSE

JOptionPane

通过JOptionPane可以非常方便地创建一些简单的对话框,JOptionPane提供了如下4个方法来创建对话框。
  • showMessageDialog/showInternalMessageDialog:消息对话框
  • showConfirmDialog/showInternalMessageDialog:确认对话框
  • showInputDialog/showInternalInputDialog:输入对话框
  • showOptionDialog/showInternalOptionDialog:自定义选项对话框

线程

创建线程的方法
  • 定义Thread类的子类,并重写run()方法。通过调用start()方法来启动多线程
  • 实现Runnable接口创建线程类,并以此实例作为Thread的target来创建Thread对象,调用Thread对象的start()方法来启动该线程。
  • 创建Callable接口的实现类,实现call()方法,该方法有返回值,使用FutureTask类来包装Callable对象,使用FutureTask对象作为Thread对象的target创建线程对象,并启动新线程。使用FutureTask对象的get()方法来获得子线程执行结束后的返回值。
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;

public class Test implements Callable<Integer>{
	public Integer call()
	{
		int i=0;
		for(; i<10; i++)
		{
			System.out.println(Thread.currentThread().getName() + ", i = " + i);
		}
		return i;
	}
	
	public static void main(String[] args)
	{
		Test t = new Test();
		FutureTask<Integer> task = new FutureTask<Integer>(t);
		for(int i=0; i<10; i++)
		{
			System.out.println(Thread.currentThread().getName() + ", i = " + i);
			if(i == 2)
			{
				new Thread(task, "Thread with return value").start();
			}
		}
		try
		{
			System.out.println("Sub thread's return value: "+task.get());
		}
		catch(Exception e)
		{
			e.printStackTrace();
		}
	}
}

线程的生命周期

  • 新建状态,当程序使用new关键字创建了一个线程之后,该线程就出于新建状态。
  • 就绪状态,当线程对象调用了start()方法之后,线程就出于就绪状态。至于线程合适开始运行,取决于JVM里线程调度器的调度
  • 运行状态,出于就绪状态的线程获得了CPU,开始执行run()方法,就处于运行状态
  • 阻塞状态,在采用抢占式调度策略的系统中,当系统给线程的时间片用完之后,系统就会剥夺线程所占的资源,该线程进入阻塞状态,而在小型设备中系统可能采用协作式的调度策略,这时只有当一个线程调用了它的sleep()或yield()方法后才会放弃所占用的资源。
  • 死亡状态,线程会以如下3种方式结束,结束后就出于死亡状态。run()或call()方法执行完成,线程抛出一个未捕获的Exception或Error,直接调用线程的stop()方法来结束该线程

join方法

当某个程序执行流中调用其他线程的join方法时,调用线程将被阻塞,直到被join()方法加入的线程执行完为止。

后台线程

后台线程(Deamon Thread)的任务是为其他的线程提供服务,如果所有的前台线程都死亡了,后台线程自动死亡。
调用Thread对象的setDaemon(true)方法可将指定线程设置成后台线程。

yield方法

让线程从运行状态转到就绪状态。


线程同步

使用同步代码块,语法格式如下
synchronized(obj)
{
	// Codes need thread safety
}

obj称为同步监视器

同步方法
public synchronized void draw()
{
	// Codes need thread safety
}

同步方法的同步监视器是this

嵌套的同步块是安全的,如
synchronized(a)
{
	synchronized(a)
	{
	// Codes need thread safety
	}
}

同步锁

Lock对象
class X
{
	private final ReentrantLock lock = new ReentrantLock();
	
	public void m()
	{
		lock.lock();
		try{
			// Codes need thread safety
		}
		finally
		{
			lock.unlock();
		}
	}
}
ReentrantLock锁具有可重入性,线程可以对它已加锁的ReentrantLock再次加锁。lock()加锁之后必须显示调用unlock()释放锁,所以一段被锁保护的代码可以调用被相同锁保护的方法。

线程通信

 进程调用wait()阻塞自己,知道被notify()或notifyAll()唤醒。




















评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值