Java编程思想(4)

第13章 字符串

1 String对象是不可变,String类中每一个修改String值的方法实际都是创建一个全新的String对象

2 " + "与" += "是Java中仅有的两个重载过的操作符,而Java并不允许重载任何操作符。

3 mac下用Java命令

package c06;

public class ArrayApp {
	public static void main(String[] args){		
		String mango = "mango";
		String s = "abc "+mango+" def "+47;
		System.out.println(s);
	}
}

$ cd src      // 要到src目录下

$ javac c06/ArrayApp.java     //  c06为包目录名,ArrayApp.java为文件名

$ java c06.ArrayApp      // 执行ArrayApp.java

abc mango def 47         // 执行结果

$ javap -c c06.ArrayApp      // 反编译

Compiled from "ArrayApp.java"

public class c06.ArrayApp {

  public c06.ArrayApp();

    Code:

       0: aload_0

       1: invokespecial #1                  // Method java/lang/Object."<init>":()V

       4: return

 

  public static void main(java.lang.String[]);

    Code:

       0: ldc           #2                  // String mango

       2: astore_1

       3: new           #3                  // class java/lang/StringBuilder

       6: dup

       7: invokespecial #4                  // Method java/lang/StringBuilder."<init>":()V

      10: ldc           #5                  // String abc

      12: invokevirtual #6                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;

      15: aload_1

      16: invokevirtual #6                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;

      19: ldc           #7                  // String  def

      21: invokevirtual #6                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;

      24: bipush        47

      26: invokevirtual #8                  // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;

      29: invokevirtual #9                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;

      32: astore_2

      33: getstatic     #10                 // Field java/lang/System.out:Ljava/io/PrintStream;

      36: aload_2

      37: invokevirtual #11                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V

      40: return

}

4 StringBuilder,包含insert(),replace(),substring(),reverse(),append(),toString()和delete()

public class ArrayApp {
	public static Random rand = new Random(47);
	public String toString(){
		StringBuilder result = new StringBuilder("[");
		for(int i=0;i<25;i++){
			result.append(rand.nextInt(100));
			result.append(", ");
		}
		result.delete(result.length()-2, result.length());
		result.append("]");
		return result.toString();
	}
	public static void main(String[] args){		
		ArrayApp a = new ArrayApp();
		System.out.println(a);
	}
}

5 如果要打印对象的内存地址,可以使用this关键字。但如下所示,编译器看到String对象后面跟个"+",会试着把this转换成一个String,然后调用this.toString()就进入了循环的递归。所以此处得用super.toString()代替this

public class ArrayApp {
	public static Random rand = new Random(47);
	public String toString(){
		//return "address: "+this+"\n";
		return "address: "+super.toString()+"\n";
	}
	public static void main(String[] args){		
		List<ArrayApp> t = new ArrayList<ArrayApp>();
		for(int i=0;i<10;i++)
			t.add(new ArrayApp());
	
			System.out.println(t);
	}
}

6 String的操作

方法参数,重载版本应用
构造器重载版本:默认版本,String,StringBuilder,StringBuffer,char数组,byte数组创建String对象
length() String中字符的个数
charAt()参数:int索引取得String中该索引位置上的char
getChars(),getBytes()参数:要复制部分的起点和终点的索引,复制的目标数组,目标数组的起始索引复制char或byte到一个目标数组中
toCharArray() 生成一个char[ ],包含String的所有字符
equals()参数:与之比较的String比较两个String内容是否相同,相同则返回true
compareTo()参数:与之比较的String按词典顺序比较String内容大小,结果为负数,零或正数
contains()参数:要搜索的CharSequenceString对象包含参数内容则返回true
contentEquals()参数:与之比较的CharSequence或StringBufferString对象与参数内容完全一致则返回true
equalsIgnoreCase()参数:与之比较的String忽略大小写,比较两个String内容是否相同,相同则返回true
regionMatcher()参数:该String的索引偏移量,另一个String及其索引偏移量,要比较长度返回boolean结果,以表明所比较区域是否相等
startsWith()参数:起始String返回boolean结果,以表明该String是否以此参数起始
endsWith()参数:后缀String返回boolean结果,以表明该String是否以此参数后缀
indexOf(),lastIndexOf()重载版本:char,char与起始索引,String,String与起始索引如果不包含参数则返回-1,否则返回该参数在String中的起始索引。lastIndexOf()是从后往前搜索
substring()重载版本:起始索引,起始索引和终点坐标返回一个新的子String,包含参数指定区域的字符串
concat()参数:要连接的String返回新的String,内容为原始String连接参数String
replace()参数:要替换掉的字符返回替换后的新String
toLowerCase(),toUpperCase() String全部变成小写/大写字符
trim() 去掉String两端空白字符,返回新String
valueOf()重载版本:Object;char[];char[]和偏移量和字符个数;boolean;char;int;float;long;double返回表示参数内容的String,即将其他类型转换为String类型
intern() 为每个唯一的字符序列生成一个且仅生成一个String引用

7 格式化输出,如下所示三者输出结果一样

int x = 5;
double y = 5.332542;
System.out.println("Row 1: ["+x+" "+y+"]");
System.out.printf("Row 1: [%d %f]\n",x,y);
System.out.format("Row 1: [%d %f]\n",x,y);

8 在Java中,所有新的格式化功能都由java.util.Formatter类处理。可以将Formatter看作一个翻译器,将格式化字符串与数据翻译成需要的结果。Formatter类将内容翻译为字符串,由PrintStream进行输出

public class ArrayApp {
	private String name;
	private Formatter f;
	public ArrayApp(String name,Formatter f){
		this.name = name;
		this.f = f;
	}
	public void move(int x,int y){
		f.format("%s The ArrayApp is at (%d,%d)\n", name,x,y);
	}
	public static void main(String[] args){		
		PrintStream outAlias = System.out;
		ArrayApp tommy = new ArrayApp("Tommy",new Formatter(System.out));
		ArrayApp terry = new ArrayApp("Terry",new Formatter(outAlias));
		tommy.move(0, 0);
		terry.move(4, 3);
		tommy.move(3, 4);
		terry.move(2, 5);
		tommy.move(3, 3);
		terry.move(3, 3);
	}
}

9 格式化说明符,语法如下

%[argument_index$][flags][width][.precision]conversion      //  precision前面有个小数点

注:

  • width控制一个域的最小尺寸。默认情况是右对齐,但可以通过使用“-“标志来改变对齐方向。width可以应用于各种数据类型
  • 不是所有类型都能使用precision,而且不同类型使用情况也不一样。将precision用于String时表示打印String时输出字符的最大数量,用于float表示小数点后位数(默认6位小数)。precision不能用于整数,会触发异常
public class ArrayApp {
	private double total = 0;
	private Formatter f = new Formatter(System.out);
	public void printTitle(){
		f.format("%-15s %5s %10s\n","Item", "Qty","Price");
		f.format("%-15s %5s %10s\n", "----","--","-----");
	}
	public void print(String name,int qty,double price){
		f.format("%-15.15s %5d %10.2f\n", name,qty,price);
		total += price;
	}
	public void printTotal(){
		f.format("%-15s %5s %10.2f\n", "Tax","",total*0.06);
		f.format("%-15s %5s %10s\n", "","","-----");
		f.format("%-15s %5s %10.2f\n", "Total","",total*1.06);
	}
	public static void main(String[] args){
		ArrayApp a = new ArrayApp();
		a.printTitle();
		a.print("Jack's Magic Beans",4,4.25);
		a.print("Princess Peas", 3, 5.1);
		a.print("Three Bears Porridge", 1, 14.29);
		a.printTotal();
	}
}


输出结果
Item              Qty      Price
----               --      -----
Jack's Magic Be     4       4.25
Princess Peas       3       5.10
Three Bears Por     1      14.29
Tax                         1.42
                           -----
Total                      25.06

10 Formatter类型转换字符

d整数型(十进制)
cUnicode字符
bBoolean值
sString
f浮点数(十进制)
e浮点数(科学计数)
x整数(十六进制)
h散列码(十六进制)
%字符"%"
Formatter f = new Formatter(System.out);
char u = 'a';
System.out.println("u = 'a'");
f.format("s: %s\n", u);      // ok, s: a
//f.format("d: %d\n", u);    //error, d != java.lang.Character
f.format("c: %c\n", u);      // ok, c: a
f.format("b: %b\n", u);      // ok, b: true
//f.format("f: %f\n", u);    // error, f != java.lang.Character
//f.format("e: %e\n", u);    // error, e != java.lang.Character
//f.format("x: %x\n", u);    // error, x != java.lang.Character
f.format("h: %h\n", u);      // ok, h: 61

int v = 121;
System.out.println("v = 121");
f.format("s: %s\n", v);     // ok, s: 121
f.format("d: %d\n", v);     // ok, d: 121
f.format("c: %c\n", v);     // ok, c: y 
f.format("b: %b\n", v);     // ok, b: true 
//f.format("f: %f\n", v);   // error, f != java.lang.Integer
//f.format("e: %e\n", v);   // error, e != java.lang.Integer
f.format("x: %x\n", v);     // ok, x: 79
f.format("h: %h\n", v);     // ok, h: 79
 
BigInteger w = new BigInteger("500000000000000000000");
System.out.println("w = 500000000000000000000");
f.format("s: %s\n", w);     // ok, s: 500000000000000000000
f.format("d: %d\n", w);     // ok, d: 500000000000000000000
//f.format("c: %c\n", w);   // error, c != java.math.BigInteger
f.format("b: %b\n", w);     // ok, b: true
//f.format("f: %f\n", w);   // error, f != java.math.BigInteger
//f.format("e: %e\n", w);   // error, e != java.math.BigInteger
f.format("x: %x\n", w);     // ok, x: 1b1ae4d6e2ef500000
f.format("h: %h\n", w);     // ok, h: 31066ab9

double x = 179.543;
System.out.println("x = 179.543");
f.format("s: %s\n", x);     // ok, s: 179.543
//f.format("d: %d\n", x);   // error, d != java.lang.Double
//f.format("c: %c\n", x);   // error, c != java.lang.Double
f.format("b: %b\n", x);     // ok, b: true
f.format("f: %f\n", x);     // ok, f: 179.543000
f.format("e: %e\n", x);     // ok, e: 1.795430e+02
//f.format("x: %x\n", x);   // error, x != java.lang.Double
f.format("h: %h\n", x);     // ok, h: 1ef462c

ArrayApp y = new ArrayApp();
System.out.println("y = new ArrayApp()");
f.format("s: %s\n", y);     // ok, s: c06.ArrayApp@146bf551
//f.format("d: %d\n", y);   // error, d != c06.ArrayApp
//f.format("c: %c\n", y);   // error, c != c06.ArrayApp
f.format("b: %b\n", y);     // ok, b: true
//f.format("f: %f\n", y);   // error, f != c06.ArrayApp
//f.format("e: %e\n", y);   // error, e != c06.ArrayApp
//f.format("x: %x\n", y);   // error, x != c06.ArrayApp
f.format("h: %h\n", y);     // ok, h: 146bf551

boolean z = false;
System.out.println("z = false");
f.format("s: %s\n", z);    // ok, s: false
//f.format("d: %d\n", z);  // error, d != java.lang.Boolean
//f.format("c: %c\n", z);  // error, c != java.lang.Boolean
f.format("b: %b\n", z);    // ok, b: false
//f.format("f: %f\n", z);  // error, f != java.lang.Boolean
//f.format("e: %e\n", z);  // error, e != java.lang.Boolean
//f.format("x: %x\n", z);  // error, x != java.lang.Boolean
f.format("h: %h\n", z);    // ok, h: 4d5

11 对于转换字符b,只要参数不为null,转换结果永远都是true,即使数字0也是true。

12 String.format(),功能跟Formatter类似,但方便不用创建类

public class ArrayApp extends Exception {
	public ArrayApp(int transactionID,int queryID,String message){
		super(String.format("(t%d,q%d) %s",transactionID,queryID,message));
	}

	public static void main(String[] args){
		try{
			throw new ArrayApp(3,7,"Write failed");
		}catch(Exception e){
			System.out.println(e);
		}
	}
}

13  “%010d” 表示输出宽度为10位的整数,如果变量不够10位,左侧添加0来补充位数

14 在Java中,“\\d”表示一位数字“-?\\d+”表示可能有一个负号,后面跟着一位或多位数字。“(-|\\+)?”表示可能有一个-或+,或者二者都没有

System.out.println("-1234".matches("-?\\d+"));    // true
System.out.println("5678".matches("-?\\d+"));     // true
System.out.println("+911".matches("-?\\d+"));     // false
System.out.println("+911".matches("(-|\\+)?\\d+"));  // true

15 "\\W"表示非单词字符“\\w”表示一个单词字符“n\\W+”表示字母n后面跟着一个或多个非单词字符

public class ArrayApp {	
	public static String knights = "Then, when you have found the shrubbery, you must "
			+"cut down the mightiest tree in the forest... "
			+ "with... a herring!";
	public static void split(String regex){
		System.out.println(Arrays.toString(knights.split(regex)));
	}		
	public static void main(String[] args){
		split(" ");
		split("\\W+");
		split("n\\W+");
	}
}

输出
[Then,, when, you, have, found, the, shrubbery,, you, must, cut, down, the, mightiest, tree, in, the, forest..., with..., a, herring!]
[Then, when, you, have, found, the, shrubbery, you, must, cut, down, the, mightiest, tree, in, the, forest, with, a, herring]
[The, whe, you have found the shrubbery, you must cut dow, the mightiest tree i, the forest... with... a herring!]

16 String类自带一个正则表达式的替换工具

public class ArrayApp {	
	public static String knights = "Then, when you have found the shrubbery, you must "
			+"cut down the mightiest tree in the forest... "
			+ "with... a herring!";
			
	public static void main(String[] args){
		System.out.println(knights.replaceFirst("f\\w+", "located"));
		System.out.println(knights.replaceAll("shrubbery|tree|herring", "banana"));
	}
}

输出
Then, when you have located the shrubbery, you must cut down the mightiest tree in the forest... with... a herring!
Then, when you have found the banana, you must cut down the mightiest banana in the forest... with... a banana!

17 字符类

点号( . )任意字符
[abc]a|b|c,包含a,b和c三者中任意字符
[^abc]除了a,b和c之外的任意字符
[a-zA-Z]从a到z或从A到Z的任意字符
[abc[hij]]a|b|c|h|i|j,任意a,b,c,h,i和j字符(并集)
[a-z&&[hij]]任意h,i或j (交集)
\s空白字符
\S非空白字符
\d数字[0-9]
\D非数字[^0-9]
\w单词字符[a-zA-Z0-9]
\W非单词字符

18 正则逻辑操作符

XYY跟在X后面
X|YX或Y
(X)捕获组

19 边界匹配符

^一行的开始
$一行的结束
\b词的边界
\B非词的边界
\G前一个匹配的结束
// 输出都是true
for(String pattern:new String[]{"Rudolph","[rR]udolph","[rR][aeiou][a-z]ol.*","R.*"})
			System.out.println("Rudolph".matches(pattern));

20 量词(X必须要用圆括号括起来)

贪婪型勉强型占有型如何匹配
X?X??X?+一个或零个X
X*X*?X*+零个或多个X
X+X+?X++一个或多个X
X{n}X{n}?X{n}+恰好n次X
X{n,}X{n,}?X{n,}+至少n次X
X{n,m}X{n,m}?X{n,m}+至少n,且不超过m次X

21 Matcher.find()在CharSequence中查找多个匹配。第二个find()能够接收一个整数作为参数,该整数表示字符串中字符的位置,并以其作为搜索的起点。

Matcher m = Pattern.compile("\\w+")
		.matcher("Evening is full of the linnet's wings");
while(m.find())
	System.out.print(m.group()+" ");
System.out.println();
int i = 0;
while(m.find(i)){
	System.out.print(m.group()+" ");
	i++;
}

Evening is full of the linnet s wings 
Evening vening ening ning ing ng g is is s full full ull ll l of of f the the he e linnet linnet innet nnet net et t s s wings wings ings ngs gs s 

22 扫描输入,readLine()读取一行

public static BufferedReader input = new BufferedReader(
		new StringReader("Sir Robin of Camelot\n22 1.61803"));
public static void main(String[] args){
	try{
		System.out.println("What is your name?");
	String name = input.readLine();
	System.out.println(name);
	System.out.println("How old are you? What is your favorite double?");
	System.out.println("(input: <age> <double>)");
	String numbers = input.readLine();
	System.out.println(numbers);
	String[] numArray = numbers.split(" ");
	int age = Integer.parseInt(numArray[0]);
	double favorite = Double.parseDouble(numArray[1]);
	System.out.format("Hi %s.\n",name);
	System.out.format("In 5 years you will be %d.\n",age+5);
	System.out.format("My favorite double is %f", favorite/2);
	}catch(IOException e){
		e.printStackTrace();
	}
}

输出
What is your name?
Sir Robin of Camelot
How old are you? What is your favorite double?
(input: <age> <double>)
22 1.61803
Hi Sir Robin of Camelot.
In 5 years you will be 27.
My favorite double is 0.809015

23 Scanner类,Scanner根据空白字符对输入进行分词。

Scanner stdin = new Scanner(System.in);
System.out.println("What is your name?");
String name = stdin.nextLine();
System.out.println(name);
System.out.println("How old are you? What is your favorite double?");
System.out.println("(input: <age> <double>)");
String numbers = stdin.nextLine();
System.out.println(numbers);
int age = stdin.nextInt();
double favorite = stdin.nextDouble();
System.out.format("Hi %s.\n",name);
System.out.format("In 5 years you will be %d.\n",age+5);
System.out.format("My favorite double is %f", favorite/2);

 

 

 

 

第14章 类型信息

1 传递this参数给System.out.println(),间接地使用toString()。把Shape子类对象放入List<Shape>的数组时会向上转型,会丢失Shape子类对象的具体类型。即对于Shape数组而言,他们只是Shape类对象。动态调用子类的draw()

abstract class Shape {
	void draw() { System.out.println(this+".draw()");}   // this即调用自身的toString()函数
	abstract public String toString();
}

class Circle extends Shape{
	public String toString(){ return "Circle";}
}

class Square extends Shape{
	public String toString(){ return "Square";}
}
class Triangle extends Shape {
	public String toString(){ return "Triangle"; }
}


public class ArrayApp {	

public static void main(String[] args){
	List<Shape>shapeList = Arrays.asList(new Circle(),new Square(),new Triangle());
	for(Shape s:shapeList)
		s.draw();
}
}

输出
Circle.draw()
Square.draw()
Triangle.draw()

2 每个类都有一个Class对象,即每当编写并且编译了一个新类,就会产生一个Class对象(更恰当地说,是被保存在一个同名的.class文件中)。为了生成这个类对象,运行这个程序的Java虚拟机(JVM)将使用被称为“类加载器”的子系统。

3 所有的类都是在对其第一次使用时,动态加载到JVM中的。当程序创建第一个对类的静态成员的引用时就会加载这个类。这个证明构造器也是类的静态方法,即使在构造器之前并没有使用static关键字。

4 类加载器首先检查这个类的Class对象是否已经加载。如果尚未加载,默认的类加载就会根据类名查找.class文件。一旦某个类的Class对象被载入内存,它就被用来创建这个类的所有对象。

package c06;

class Candy{
	static {
		System.out.println("Loading Candy");
	}
}
class NewGum {
	static {
		System.out.println("Loading Gum");
	}
}
class Cookie2{
	static {
		System.out.println("Loading Cookie");
	}
}

public class ArrayApp {	

public static void main(String[] args){
	System.out.println("inside main");
	new Candy();
	System.out.println("After creating Candy");
	//new NewGum();
	try{
		Class.forName("c06.NewGum");   // 类的全名,即包名.类名
	}catch(ClassNotFoundException e){
		System.out.println("Could not find Gum");
	}
	System.out.println("After Class.forName(\"Gum\")");
	new Cookie2();
	System.out.println("After creating Cookie");
}
}

输出
inside main
Loading Candy
After creating Candy
Loading Gum
After Class.forName("Gum")
Loading Cookie
After creating Cookie

Class.forName("类的全名(包名.类名)"),返回目标类的一个Class对象引用。

5 Class的部分函数

package c06;
interface HasBatteries {}
interface Waterproof{}
interface Shoots {}
class Toy{
	Toy() {}
	Toy(int i) {}
}
class FancyToy extends Toy implements HasBatteries,Waterproof,Shoots{
	FancyToy(){ super(1); }
}
public class ArrayApp {	

	static void printInfo(Class cc){
		System.out.println("Class name: "+cc.getName()+" is interface? ["
				+cc.isInterface()+"]");
		System.out.println("Simple name: "+cc.getSimpleName());
		System.out.println("Canonical name: "+cc.getCanonicalName());
	}
	public static void main(String[] args){
		Class c = null;
		try{
			c = Class.forName("c06.FancyToy");
		}catch(ClassNotFoundException e){
			System.out.println("Can't find FancyToy");
			System.exit(1);
		}
		printInfo(c);
		for(Class face:c.getInterfaces()){
			printInfo(face);
		}
		Class up = c.getSuperclass();
		Object obj = null;
		try{
			obj = up.newInstance();
		}catch(InstantiationException e){
			System.out.println("Cannot instantiate");
			System.exit(1);
		}catch(IllegalAccessException e){
			System.out.println("Cannot access");
			System.exit(1);
		}
		printInfo(obj.getClass());
	}
}

输出
Class name: c06.FancyToy is interface? [false]
Simple name: FancyToy
Canonical name: c06.FancyToy
Class name: c06.HasBatteries is interface? [true]
Simple name: HasBatteries
Canonical name: c06.HasBatteries
Class name: c06.Waterproof is interface? [true]
Simple name: Waterproof
Canonical name: c06.Waterproof
Class name: c06.Shoots is interface? [true]
Simple name: Shoots
Canonical name: c06.Shoots
Class name: c06.Toy is interface? [false]
Simple name: Toy
Canonical name: c06.Toy
  • forName():创建一个Class引用。在传递给forName()的字符串中,必须使用全限定名(包含包名)
  • getName():返回全限定的类名
  • getSimpleName():返回不包含包名的类名
  • getCanonicalName():返回全限定类名
  • isInterface():判断Class对象是否为接口
  • getInterface():返回Class对象里的接口Class对象
  • getSuperclass():返回Class对象的基类Class对象
  • getClass():获取对象的Class引用

newInstance()是实现"虚拟构造器"的一种途径,允许声明"我不知道你的确切类型,但是无论如何都要正确创建你自己"。使用newInstance()来创建类,必须带有默认构造器。

6 Java还提供了另一种方法来生成对Class对象的引用,即使用类字面常量,如FancyToy.class。类字面常量不仅可以应用于普通的类,也可以应用于接口,数组以及基本数据类型。对于基本数据类型的包装器类,还有一个标准字段TYPE,指向对应基本数据类型的Class对象类型。建议使用".class"的形式,与普通类保持一致

...等价于...
boolean.classBoolean.TYPE
char.classCharacter.TYPE
byte.classByte.TYPE
short.classShort.TYPE
int.classInteger.TYPE
long.classLong.TYPE
float.classFloat.TYPE
double.classDouble.TYPE
void.classVoid.TYPE

7 当使用".class"来创建对Class对象的引用时,不会自动地初始化该Class对象。为了使用类而做的准备工作实际包含了三个步骤:

  1. 加载。由类加载器执行。该步骤将查找字节码,并从这些字节码中创建一个Class对象
  2. 链接。在链接阶段将验证类中的字节码,为静态域分配存储空间,并且如果必需的话,将解析这个类创建的对其他类的所有引用。
  3. 初始化。如果该类具有超类,则对其初始化,执行静态初始化器和静态初始化块

8 如下代码所示,代码分析

Class initable = Initable.class;     //  使用.class语法仅获得对类的Class对象引用并不会引发初始化,即不会输出"Initializing Initable"

System.out.println("After creating Initable ref");

System.out.println(Initable.staticFinal);  // 如果一个static final值是编译器常量,如staticFinal,无须对Initable初始化即可读取

System.out.println(Initable.staticFinal2); // 但staticFinal2不是编译器常量,使用需要初始化Initable才能读取,即会输出"Initializing Initable"

System.out.println(Initable2.staticNonFinal); // 如果一个static成员变量不是final,它被读取前必须要先进行链接和初始化

try{

Class initable3 = Class.forName("c06.Initable3");  // 获得Class对象引用同时还会引发初始化

}catch(Exception e){

e.printStackTrace();

}

System.out.println("After creating Initable3 ref");

System.out.println(Initable3.staticNonFinal);

class Initable{
	static final int staticFinal = 47;
	static final int staticFinal2 = ArrayApp.rand.nextInt(1000);
	static {
		System.out.println("Initializing Initable");
	}
}
class Initable2{
	static int staticNonFinal = 147;
	static {
		System.out.println("Initializing Initable2");
	}
}
class Initable3{
	static int staticNonFinal = 74;
	static {
		System.out.println("Initializing Initable3");
	}
}
public class ArrayApp {	

	public static Random rand = new Random(47);
	public static void main(String[] args){
		Class initable = Initable.class;
		System.out.println("After creating Initable ref");
		System.out.println(Initable.staticFinal);
		System.out.println(Initable.staticFinal2);
		System.out.println(Initable2.staticNonFinal);
		try{
		Class initable3 = Class.forName("c06.Initable3");
		}catch(Exception e){
			e.printStackTrace();
		}
		System.out.println("After creating Initable3 ref");
		System.out.println(Initable3.staticNonFinal);
	}
}

输出
After creating Initable ref
47
Initializing Initable
258
Initializing Initable2
147
Initializing Initable3
After creating Initable3 ref
74

9 Class引用表示的就是它所指向的对象的确切类型,而该对象便是Class类的一个对象。泛型类引用只能赋值为指向其声明的类型,编译器会强制执行额外的类型检查,如genericIntClass不能赋值double.class。而普通的类引用可以重新被赋值为指向任何其他的Class对象,如intClass

Class intClass = int.class;
Class<Integer> genericIntClass = int.class;
genericIntClass = Integer.class;
intClass = double.class;
genericIntClass = double.class;   // error

10 因为Integer继承于Number,但Integer Class对象并不是Number Class对象的子类。可以使用通配符"?"来说放松限制。

Class<Number> g = int.class;   // error
Class<?> k = int.class;    // ok
k = double.class;          // ok

11 为了创建一个Class引用,且限定为某种类型或该类型的任何子类型,可以将通配符与extends关键字结合,创建一个范围

Class<? extends Number> k = int.class;
k = double.class;
k = Number.class;

12 Class引用的转型语法,即cast()函数

class Building{}
class House extends Building{}
public class ArrayApp {	

	public static void main(String[] args){
		Building b = new House();
		Class<House> houseType = House.class;
		House h = houseType.cast(b);   // 等价于h = (House)b
		h = (House)b;
	}
}

13 RTTI在Java中还有第三种形式,即关键字instanceof,返回一个布尔值,判断对象是否为某个类型的实例。如下所示,在将x转型为一个Dog前,先判断对象x是否从属于Dog类。

if(x instanceof Dog)
   ((Dog)x).bark();

14 工厂方法设计模式 ?

15 instanceof和isInstance()判断结果一样,equals()和==判断结果也一样。instanceof保持了类型的概念,它表示“你是这个类吗,或者这个类的子类吗”

class Base{}
class Derived extends Base{}
public class ArrayApp {	
	static void test(Object x){
		System.out.println("Testing x of type "+x.getClass());
		System.out.println("x instanceof Base "+(x instanceof Base));
		System.out.println("x instanceof Derived " +(x instanceof Derived));
		System.out.println("Base.isInstance(x) "+Base.class.isInstance(x));
		System.out.println("Derived.isInstance(x) "+Derived.class.isInstance(x));
		System.out.println("x.getClass() == Base.class "+(x.getClass() == Base.class));
		System.out.println("x.getClass() == Derived.class "+(x.getClass() == Derived.class));
		System.out.println("x.getClass().equals(Base.class) "+(x.getClass().equals(Base.class)));
		System.out.println("x.getClass().equals(Derived.class) "+(x.getClass().equals(Derived.class)));

	}
	public static void main(String[] args){
		test(new Base());
		test(new Derived());
	}

}

输出
Testing x of type class c06.Base
x instanceof Base true
x instanceof Derived false
Base.isInstance(x) true
Derived.isInstance(x) false
x.getClass() == Base.class true
x.getClass() == Derived.class false
x.getClass().equals(Base.class) true
x.getClass().equals(Derived.class) false
Testing x of type class c06.Derived
x instanceof Base true
x instanceof Derived true
Base.isInstance(x) true
Derived.isInstance(x) true
x.getClass() == Base.class false
x.getClass() == Derived.class true
x.getClass().equals(Base.class) false
x.getClass().equals(Derived.class) true

16 反射,Class的getMethods()和getConstructors()函数分别返回Method对象数组和Constructor对象数组

public class ArrayApp {	
	private static String usage = "usage:\n"
			+"ShowMethods qualified.class.name\n"+
			"To show all methods in class or:\n"+
			"ShowMethods qualified.class.name word\n"+
			"To search for methods involving 'word'";
	private static Pattern p = Pattern.compile("\\w+\\.");
	public static void main(String[] args){
		if(args.length < 1) {
			System.out.println(usage);
			System.exit(0);
		}
		int lines = 0;
		try{
			Class<?> c = Class.forName(args[0]);
			Method[] methods = c.getMethods();
			Constructor[] ctors = c.getConstructors();
			if(args.length == 1){
				for(Method m:methods)
					System.out.println(p.matcher(m.toString()).replaceAll(""));
				for(Constructor ct:ctors)
					System.out.println(p.matcher(ct.toString()).replaceAll(""));
				lines = methods.length + ctors.length;
			}else {
				for(Method m:methods)
					if(m.toString().indexOf(args[1]) != -1){
						System.out.println(p.matcher(m.toString()).replaceAll(""));
						lines++;
					}
				for(Constructor ct:ctors)
					if(c.toString().indexOf(args[1]) != -1){
						System.out.println(p.matcher(ct.toString()).replaceAll(""));
						lines++;
					}
			}
		}catch(ClassNotFoundException e){
			System.out.println("No such class: "+e);
		}
	}
}

17 代理是基本的设计模式之一,它是为了提供额外的或不同的操作,而插入的用来代替“实际”对象的对象。这些操作通常涉及与“实际”对象的通信,因此代理通常充当着中间人的角色。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值