深入解析JAVA细节(J2SE)

JAVA SE Lesson 1

1. 类是一种抽象的概念,对象是类的一种具体表示形式,是具体的概念。先有类,然后由类来生成对象(Object)。对象又叫做实例(Instance)。

2. 类由两大部分构成:属性以及方法。属性一般用名词来表示,方法一般用动词来表示。

3. 如果一个java源文件中定义了多个类,那么这些类中最多只能有一个类是public的,换句话说,定义的多个类可以都不是public的。

4. 在Java中进行方法的参数传递时,无论传递的是原生数据类型还是引用类型,参数传递方式统一是传值(pass by value)。Java中没有传引用(pass by reference)的概念。

5. 方法重载(Overload)。表示两个或多个方法名字相同,但方法参数不同。方法参数不同有两层含义:1)参数个数不同。2)参数类型不同。 注意:方法的返回值对重载没有任何影响。

6. 构造方法重载:只需看参数即可。如果想在一个构造方法中调用另外一个构造方法,那么可以使用this()的方式调用,this()括号中的参数表示目标构造方法的参数。this()必须要作为构造方法的第一条语句,换句话说,this()之前不能有任何可执行的代码。

7. 继承(Inheritence):Java是单继承的,意味着一个类只能从另一个类继承(被继承的类叫做父类【基类,base class】, 继承的类叫做子类),Java中的继承使用extends关键字。

 

8. 当生成子类对象时,Java默认首先调用父类的不带参数的构造方法,然后执行该构造方法,生成父类的对象。接下来,再去调用子类的构造方法,生成子类的对象。【要想生成子类的对象,首先需要生成父类的对象,没有父类对象就没有子类对象。比如说:没有父亲,就没有孩子】。

9. super关键字:super表示对父类对象的引用。

10. 如果子类使用super()显式调用父类的某个构造方法,那么在执行的时候就会寻找与super()所对应的构造方法而不会再去寻找父类的不带参数的构造方法。与this一样,super也必须要作为构造方法的第一条执行语句,前面不能有其他可执行语句。

11. 关于继承的3点:

a) 父类有的,子类也有

b) 父类没有的,子类可以增加

c) 父类有的,子类可以改变

12. 关于继承的注意事项

a) 构造方法不能被继承

b) 方法和属性可以被继承

c) 子类的构造方法隐式地调用父类的不带参数的构造方法

d) 当父类没有不带参数的构造方法时,子类需要使用super来显式地调用父类的构造方法,super指的是对父类的引用

e) super关键字必须是构造方法中的第一行语句。

 

13.方法重写(Override):又叫做覆写,子类与父类的方法返回类型一样、方法名称一样,参数一样,这样我们说子类与父类的方法构成了重写关系。

14.方法重写与方法重载之间的关系:重载发生在同一个类内部的两个或多个方法。重写发生在父类与子类之间。

15.当两个方法形成重写关系时,可以在子类方法中通过super.run()形式调用父类的run()方法,其中super.run()不必放在第一行语句,因此此时父类对象已经构造完毕,先调用父类的run()方法还是先调用子类的run()方法是根据程序的逻辑决定的。

16.在定义一个类的时候,如果没有显式指定该类的父类,那么该类就会继承于java.lang.Object类(JDK提供的一个类,Object类是Java中所有类的直接或间接父类)。

17. 多态(Polymorphism):我们说子类就是父类(玫瑰是花,男人是人),因此多态的意思就是:父类型的引用可以指向子类的对象。

 

18.接口中的方法都不能有实现,修饰符只能是public、abstract的。当什么也没写的时候,就以默认为publicabstract。这意味着接口中的方法不能是final、static的。

 

19.接口中允许包含常量,我们定义的成员变量前面没有写任何的修饰符时,会被自动的设置为public static final,实际上是一个常量,

当然实现该接口的类就具有了这个常量。

//---------------------------------------------------------

20接口中也不能有静态的代码块。

 

21接口还可以继承其他的接口。

 

22实现接口可以是多实现的,即一个类可以实现多个接口。

23Comparable是一个接口,中有comparaTo(Object obj)方法,实现这个接口的非abstract类,需要重写这个方法。返回值是一个int型的数。

 

24对象的克隆,实现Cloneable接口,并且重写clone()方法,clone()是Object类中的protected方法。如果在没有实现Cloneable 接口的实例上调用 Object的clone方法,则会抛出CloneNotSupportedException 异常。实现Cloneable接口意味着取得了克隆的权利。

 

25.Clone是浅拷贝。如果类中有引用类型的变量,要实现深拷贝,可以参考示例:

 

 

@Override

protected Object clone() throws CloneNotSupportedException {

    Student2s = (Student2)super.clone();

    Teachert = (Teacher)s.getTeacher().clone();//s换成this效果是一样的

    s.setTeacher(t);

 return s;

}

 

26内部类:内部类方法可以访问该类定义的所有作用域的数据,包括私有的数据。内部类可以对同一个包中的其他类隐藏起来。当想要定义一个回调函数且不想编写大量的代码时,使用匿名的内部内比较便捷。

 

27内部类即可以访问自身的数据域,也可以访问创建它的外围类对象的数据域。

 

28局部内部类是写在一个函数中的类,这样就只能在这个函数中使用这个内部类,局部内部类具有极高的隐藏性。

29对于局部内部类,还有一个优点,他们不仅能够访问包含它们的内部类,还可以访问局部变量。不过,那些局部变量必须被申明为final。

30匿名内部类,比如:ActionListener listener = new ActionListener() {},意思是创建一个实现了ActionLister接口的对象。这个类是没有名字的。

31静态的内部类,就像是静态的方法一样,只能访问静态的方法及变量。

 

Exception:

32主要分为运行时异常即RuntimeException,与其他异常。

 

 

成员变量没有多态(当然是有继承的):

class A{

    int i = 10;

}

class B extends A{

    int j = 4;

    int i = 20;

}

 

 

class Test {

    public static void main(String[] args) {

       Ab = new B();

       System.out.println(b.i);

    }

}

 

 

 

 

Java SE Lesson 2

1. 多态:父类型的引用可以指向子类型的对象。

2. Parent p = new Child();当使用多态方式调用方法时,首先检查父类中是否有sing()方法,如果没有则编译错误;如果有,再去调用子类的sing()方法。

3. 一共有两种类型的强制类型转换:

a) 向上类型转换(upcast):比如说将Cat类型转换为Animal类型,即将子类型转换为父类型。对于向上类型转换,不需要显式指定。

b) 向下类型转换(downcast):比如将Animal类型转换为Cat类型。即将父类型转换为子类型。对于向下类型转换,必须要显式指定(必须要使用强制类型转换)

4. 抽象类(abstract class):使用了abstract关键字所修饰的类叫做抽象类。抽象类无法实例化,也就是说,不能new出来一个抽象类的对象(实例)。

 

5. 抽象方法(abstract method):使用abstract关键字所修饰的方法叫做抽象方法。抽象方法需要定义在抽象类中。相对于抽象方法,之前所定义的方法叫做具体方法(有声明,有实现)。

 

6. 如果一个类包含了抽象方法,那么这个类一定是抽象类。

 

7. 如果某个类是抽象类,那么该类可以包含具体方法(有声明、有实现)。

 

8. 如果一个类中包含了抽象方法,那么这个类一定要声明成abstract class,也就是说,该类一定是抽象类;反之,如果某个类是抽象类,那么该类既可以包含抽象方法,也可以包含具体方法。

 

9. 无论何种情况,只要一个类是抽象类,那么这个类就无法实例化。

 

10. 在子类继承父类(父类是个抽象类)的情况下,那么该子类必须要实现父类中所定义的所有抽象方法;否则,该子类需要声明成一个abstract class。

 

11. 接口(interface):接口的地位等同于class,接口中的所有方法都是抽象方法。在声明接口中的方法时,可以使用abstract关键字,也可以不使用。通常情况下,都会省略掉abstract关键字。

 

12. 可以将接口看作是特殊的抽象类(抽象类中可以有具体方法,也可以有抽象方法,而接口中只能有抽象方法,不能有具体方法)。

13. 类可以实现接口。实现使用关键字implements表示,代表了某个类实现了某个接口。

 

14. 一个类实现了某个接口,那么该类必须要实现接口中声明的所有方法。如果该类是个抽象类,那么就无需实现接口中的方法了。

 

15. Java是单继承的,也就是说某个类只能有唯一一个父类;一个类可以实现多个接口,多个接口之间使用逗号分隔。

 

16. 多态:所谓多态,就是父类型的引用可以指向子类型的对象,或者接口类型的引用可以指向实现该接口的类的实例。关于接口与实现接口的类之间的强制类型转换方式与父类和子类之间的强制类型转换方式完全一样。

 

17. static关键字:可以用于修饰属性,也可以用于修饰方法,还可以用于修饰类(后面的课程讲)(静态的内部类,就像是静态的方法一样,只能访问静态的方法及变量。)

18. static修饰属性:无论一个类生成了多少个对象,所有这些对象共同使用唯一一份静态的成员变量;一个对象对该静态成员变量进行了修改,其他对象的该静态成员变量的值也会随之发生变化。如果一个成员变量是static的,那么我们可以通过类名.成员变量名的方式来使用它(推荐使用这种方式)。

 

19. static修饰方法:static修饰的方法叫做静态方法。对于静态方法来说,可以使用类名.方法名的方式来访问。

 

20. 静态方法只能继承,不能重写(Override)。

 

21. final关键字:final可以修饰属性、方法、类。

 

22. final修饰类:当一个类被final所修饰时,表示该类是一个终态类,即不能被继承。

 

23. final修饰方法:当一个方法被final所修饰时,表示该方法是一个终态方法,即不能被重写(Override)。

 

24. final修饰属性:当一个属性被final所修饰时,表示该属性不能被改写。

 

25. 当final修饰一个原生数据类型时,表示该原生数据类型的值不能发生变化(比如说不能从10变为20);如果final修饰一个引用类型时,表示该引用类型不能再指向其他对象了,但该引用所指向的对象的内容是可以发生变化的。

 

26. 对于final类型成员变量,一般来说有两种赋初值方式:

a) 在声明final类型的成员变量时就赋上初值

b) 在声明final类型的成员变量时不赋初值,但在类的所有构造方法中都为其赋上初值。

 

27. static代码块:静态代码块。静态代码块的作用也是完成一些初始化工作。首先执行静态代码块,然后执行构造方法。静态代码块在类被加载的时候执行,而构造方法是在生成对象的时候执行;要想调用某个类来生成对象,首先需要将类加载到Java虚拟机上(JVM),然后由JVM加载这个类来生成对象。

 

28. 类的静态代码块只会执行一次,是在类被加载的时候执行的,因为每个类只会被加载一次,所以静态代码块也只会被执行一次;而构造方法则不然,每次生成一个对象的时候都会调用类的构造方法,所以new一次就会调用构造方法一次。

 

29. 如果继承体系中既有构造方法,又有静态代码块,那么首先执行最顶层的类的静态代码块,一直执行到最底层类的静态代码块,然后再去执行最顶层类的构造方法,一直执行到最底层类的构造方法。注意:静态代码块只会执行一次。

 

30. 不能在静态方法中访问非静态成员变量;可以在静态方法中访问静态的成员变量。可以在非静态方法中访问静态的成员变量。

 

31. 总结:静态的只能访问静态的;非静态的可以访问一切。

 

32. 不能在静态方法中使用this关键字。

 

Java SE Lesson 3

1. 接口中所声明的方法都是抽象方法。接口中的方法都是public的。

 

2. 接口中也可以定义成员变量。接口中的成员变量都是public、final、static的。

 

3. 一个类不能既是final,又是abstract的。因为abstract的主要目的是定义一种约定,让子类去实现这种约定,而final表示该类不能被继承,这样abstract希望该类可以被继承而final明确说明该类不能被继承,两者矛盾。因此一个类不能既是final的,又是abstract的。

 

4. DesignPattern(设计模式)。单例模式(Singleton):表示一个类只会生成唯一的一个对象。

 

5. 包(package)。用于将完成不同功能的类分门别类,放在不同的目录(包)下。包的命名规则:将公司域名反转作为包名。www.shengsiyuan.com,com.shengsiyuan(包名),对于包名:每个字母都需要小写。如果定义类的时候没有使用package,那么Java就认为我们所定义的类位于默认包里面(default package)。

 

6. 编译带有package声明的Java源文件有两种方式:

a) 直接编译,然后根据类中所定义的包名,逐一手工建立目录结构,最后将生成的class文件放到该目录结构中(很少使用,比较麻烦)。

b) 使用编译参数–d,方式为javac –d . 源文件.java,这样在编译后,编译器会自动帮助我们建立好包所对应的目录结构。

 

7. 有两个包名,分别是aa.bb.cc与aa.bb.cc.dd,那么我们称后者为前者的子包。

 

8. 导入(import),将使用package分离的各个类导入回来,让编译器能够找到所需要的类。

 

9.import的语法:import com.shengsiyuan.PackageTest;

 

10.import com.shengsiyuan.*,表示导入com.shengsiyuan包下面的所有类。

 

11. import aa.bb.*并不会导入aa.bb.cc包下面的类。这时需要这样写:

import aa.bb.*;

import aa.bb.cc.*;

 

12.关于package、import、class的顺序问题:

a) 首先需要定义包(package),可选

b) 接下来使用import进行导入,可选

c) 然后才是class或interface的定义。

 

13.如果两个类在同一个包下面,那么则不需要导入,直接使用即可。

 

14.访问修饰符(access modifier)。

1) public(公共的):被public所修饰的属性和方法可以被所有类访问。

2) protected(受保护的):被protected所修饰的属性和方法可以在类内部、相同包以及该类的子类所访问。

3) private(私有的):被private所修饰的属性和方法只能在该类内部使用

4) 默认的(不加任何访问修饰符):在类内部以及相同包下面的类所使用。

 

15.instanceof:判断某个对象是否是某个类的实例。语法形式:引用名instanceof 类名(接口名),返回一个boolean值。

 

16.People people = new Man();

 

17.System.out.println(people instanceof People);//结果为true,因为Man是People的子类,根据继承,子类就是父类,因此Man也可以看作是People的实例。

 

18. 相等性的比较(==)

1) 对于原生数据类型来说,比较的是左右两边的值是否相等。

2) 对于引用类型来说,比较左右两边的引用是否指向同一个对象,或者说左右两边的引用地址是否相同。

 

19.java.lang.Object类。java.lang包在使用的时候无需显式导入,编译时由编译器自动帮助我们导入。

 

20.API (Application Programming Interface),应用编程接口。

 

21.当打印引用时,实际上会打印出引用所指对象的toString()方法的返回值,因为每个类都直接或间接地继承自Object,而Object类中定义了toString(),因此每个类都有toString()这个方法。

 

22.关于进制的表示:16进制,逢16进一,16进制的数字包括:0~9,A,B,C,D,E,F,

 

23. equals()方法,该方法定义在Object类当中,因此Java中的每个类都具有该方法,对于Object类的equals()方法来说,它是判断调用equals()方法的引用与传进来的引用是否一致,即这两个引用是否指向的是同一个对象。对于Object类的equals()方法来说,它等价于==。

 

24. 对于String类的equals()方法来说,它是判断当前字符串与传进来的字符串的内容是否一致。

 

25.对于String对象的相等性判断来说,请使用equals()方法,而不要使用==。

 

26.String是常量,其对象一旦创建完毕就无法改变。当使用+拼接字符串时,会生成新的String对象,而不是向原有的String对象追加内容。

27.String Pool(字符串池)

 

28.String s = “aaa”;(采用字面值方式赋值)

1) 查找String Pool中是否存在“aaa”这个对象,如果不存在,则在String Pool中创建一个“aaa”对象,然后将String Pool中的这个“aaa”对象的地址返回来,赋给引用变量s,这样s会指向String Pool中的这个“aaa”字符串对象

2) 如果存在,则不创建任何对象,直接将String Pool中的这个“aaa”对象地址返回来,赋给s引用。

 

29.String s = new String(“aaa”);

1) 首先在String Pool中查找有没有“aaa”这个字符串对象,如果有,则不在String Pool中再去创建“aaa”这个对象了,直接在堆中(heap)中创建一个“aaa”字符串对象,然后将堆中的这个“aaa”对象的地址返回来,赋给s引用,导致s指向了堆中创建的这个“aaa”字符串对象。

2) 如果没有,则首先在String Pool中创建一个“aaa“对象,然后再在堆中(heap)创建一个”aaa“对象,然后将堆中的这个”aaa“对象的地址返回来,赋给s引用,导致s指向了堆中所创建的这个”aaa“对象。

 

 

JavaSE Lesson 4

1.包装类(WrapperClass)。针对于原生数据类型的包装。所有的包装类(8个)都位于java.lang包下。Java中的8个包装类分别是:Byte, Short, Integer, Long, Float, Double, Character, Boolean。他们的使用方式都是一样的,可以实现原生数据类型与包装类型的双向转换。

 

2.数组(Array):相同类型数据的集合就叫做数组。

 

3. 如何定义数组。type[] 变量名= new type[数组中元素的个数];可以按照下列方式定义长度为10的数组:

int[] a = new int[10];或者int a[] = new int[10];

 

3.数组中的元素索引是从0开始的。对于数组来说,最大的索引==数组的长度–1。

 

4.定义数组的第3种方式:type[] 变量名= {new type[]}{逗号分隔的初始化值列表};

 

5.Java中的每个数组都有一个名为length的属性,表示数组的长度。length属性是public,final,int的。数组长度一旦确定,就不能改变大小。

 

7. int[] a = new int[10],其中a是一个引用,它指向了生成的数组对象的首地址,数组中每个元素都是int类型,其中仅存放数据值本身。

北京圣思园科技有限公司版权所有

 

Java SE Lesson 5

1. 对于Java中的常量的命名规则:所有单词的字母都是大写,如果有多个单词,那么使用下划线连接即可。比如说:

 

public static finalint AGE_0F_PERSON = 20;

2. 在Java中声明final常量时通常都会加上static关键字,这样对象的每个实例都会访问唯一一份常量值。

 

3.IDE(Integrated Development Environment),集成开发环境。

1) NetBeans。http://netbeans.org/,最高版本是6.9.1

2) JBuilder。

3) Intellij IDEA

4) Eclipse(日蚀、月蚀),最高版本3.6.1

4. 集合中存放的依然是对象的引用而不是对象本身。

 

6. ArrayList底层采用数组实现,当使用不带参数的构造方法生成ArrayList对象时,实际上会在底层生成一个长度为10的Object类型数组

 

7. 如果增加的元素个数超过了10个,那么ArrayList底层会新生成一个数组,长度为原数组的1.5倍+1,然后将原数组的内容复制到新数组当中,并且后续增加的内容都会放到新数组当中。当新数组无法容纳增加的元素时,重复该过程。

 

8. 对于ArrayList元素的删除操作,需要将被删除元素的后续元素向前移动,代价比较高。

 

9. 集合当中只能放置对象的引用,无法放置原生数据类型,我们需要使用原生数据类型的包装类才能加入到集合当中。

 

10.     集合当中放置的都是Object类型,因此取出来的也是Object类型,那么必须要使用强制类型转换将其转换为真正的类型(放置进去的类型)。

 

10.关于ArrayList与LinkedList的比较分析

a)ArrayList底层采用数组实现,LinkedList底层采用双向链表实现。

b) 当执行插入或者删除操作时,采用LinkedList比较好。

c) 当执行搜索操作时,采用ArrayList比较好。

 

11.     作业:独立分析LinkedList源代码。

 

Java SE Lesson 6

1. 当向ArrayList添加一个对象时,实际上就是将该对象放置到了ArrayList底层所维护的数组当中;当向LinkedList中添加一个对象时,实际上LinkedList内部会生成一个Entry对象,该Entry对象的结构为:

Entry

{

Entry previous;

Object element;

Entry next;

}

其中的Object类型的元素element就是我们向LinkedList中所添加的元素,然后Entry又构造好了向前与向后的引用previous、next,最后将生成的这个Entry对象加入到了链表当中。换句话说,LinkedList中所维护的是一个个的Entry对象。

 

2. 关于Object类的equals方法的特点

a) 自反性:x.equals(x)应该返回true

b) 对称性:x.equals(y)为true,那么y.equals(x)也为true。

c) 传递性:x.equals(y)为 true并且y.equals(z)为true,那么x.equals(z)也应该为true。

d) 一致性:x.equals(y)的第一次调用为true,那么x.equals(y)的第二次、第三次、第n次调用也应该为true,前提条件是在比较之间没有修改x也没有修改y。

e) 对于非空引用x,x.equals(null)返回false。

3. 关于Object类的hashCode()方法的特点:

a) 在Java应用的一次执行过程当中,对于同一个对象的hashCode方法的多次调用,他们应该返回同样的值(前提是该对象的信息没有发生变化)。

b) 对于两个对象来说,如果使用equals方法比较返回true,那么这两个对象的hashCode值一定是相同的。

c) 对于两个对象来说,如果使用equals方法比较返回false,那么这两个对象的hashCode值不要求一定不同(可以相同,可以不同),但是如果不同则可以提高应用的性能。

d) 对于Object类来说,不同的Object对象的hashCode值是不同的(Object类的hashCode值表示的是对象的地址)。

 

4. 当使用HashSet时,hashCode()方法就会得到调用,判断已经存储在集合中的对象的hash code值是否与增加的对象的hash code值一致;如果不一致,直接加进去;如果一致,再进行equals方法的比较,equals方法如果返回true,表示对象已经加进去了,就不会再增加新的对象,否则加进去。

 

5. 如果我们重写equals方法,那么也要重写hashCode方法,反之亦然。

 

6. Map(映射):Map的keySet()方法会返回key的集合,因为Map的键是不能重复的,因此keySet()方法的返回类型是Set;而Map的值是可以重复的,因此values()方法的返回类型是Collection,可以容纳重复的元素。

 

7. 作业:参见Lesson 4的要求,使用集合实现,不允许使用数组。

 

8. 策略模式(Strategy Pattern)。通过查询资料掌握策略模式的原理。

 

9. 阅读TreeMap的帮助文档,自己写一个程序,练习TreeMap的使用方式并且自己定义一个Comparator。

 

Java SE Lesson 7

1. 有这样一个类:

// getter andsetter

要求:假如有若干个类Person对象存在一个List当中,对他们进行排序,分别按照名字、年龄、id进行排序(要有正序与倒序两种排序方式)。假如年龄或者姓名重复,按照id的正序进行排序。要求使用策略模式进行。

 

2. HashSet底层是使用HashMap实现的。当使用add方法将对象添加到Set当中时,实际上是将该对象作为底层所维护的Map对象的key,而value则都是同一个Object对象(该对象我们用不上);

 

3. HashMap底层维护一个数组,我们向HashMap中所放置的对象实际上是存储在该数组当中;

 

4. 当向HashMap中put一对键值时,它会根据key的hashCode值计算出一个位置,该位置就是此对象准备往数组中存放的位置。

 

5. 如果该位置没有对象存在,就将此对象直接放进数组当中;如果该位置已经有对象存在了,则顺着此存在的对象的链开始寻找(Entry类有一个Entry类型的next成员变量,指向了该对象的下一个对象),如果此链上有对象的话,再去使用equals方法进行比较,如果对此链上的某个对象的equals方法比较为false,则将该对象放到数组当中,然后将数组中该位置以前存在的那个对象链接到此对象的后面。

 

6. HashMap的内存实现布局:

 

7. 所谓泛型:就是变量类型的参数化。

 

 

 

Java SELesson 8

1.    当遍历集合或数组时,如果需要访问集合或数组的下标,那么最好使用旧式的方式来实现循环或遍历,而不要使用增强的for循环,因为它丢失了下标信息。

 

2.    Integer类有一个缓存,它会缓存介于-128~127之间的整数。

 

3.    可变参数:可变参数本质上就是一个数组,对于某个声明了可变参数的方法来说,我们既可以传递离散的值,也可以传递数组对象。但如果将方法中的参数定义为数组,那么只能传递数组对象而不能传递离散的值。

 

4.    可变参数必须要作为方法参数的最后一个参数,即一个方法不可能具有两个或两个以上的可变参数。

 

5.    枚举(Enum):我们所定义的每个枚举类型都继承自java.lang.Enum类,枚举中的每个成员默认都是public static final的。

 

6. 而每个枚举的成员其实就是您定义的枚举类型的一個实例(Instance)。换句话说,当定义了一个枚举类型后,在编译时刻就能确定该枚举类型有几个实例,分别是什么。在运行期间我们无法再使用该枚举类型创建新的实例了,这些实例在编译期间就已经完全确定下来了。

7. 静态导入:

a) import static com.shengsiyuan.common.Common.Age;

b) import static com.shengsiyuan.common.Common.output;

 

8. 表示导入Common类中的静态成员变量AGE以及静态方法output。注意:使用import static时,要一直导入到类中的静态成员变量或静态方法。

9. Java中,无论生成某个类的多少个对象,这些对象都会对应于同一个Class对象。

 

 

 

Java SE Lesson 9

 

1.    要想使用反射,首先需要获得待处理类或对象所对应的Class对象。

 

2. 获取某个类或某个对象所对应的Class对象的常用的3种方式:

a) 使用Class类的静态方法forNameClass.forName(“java.lang.String”);

b) 使用类的.class语法:String.class;

c) 使用对象的getClass()方法:String s = “aa”; Class<?> clazz = s.getClass();

 

3. 若想通过类的不带参数的构造方法来生成对象,我们有两种方式:

a) 先获得Class对象,然后通过该Class对象的newInstance()方法直接生成即可:

 

Class<?> classType =String.class;

Object obj = classType.newInstance();

b) 先获得Class对象,然后通过该对象获得对应的Constructor对象,再通过该Constructor对象的newInstance()方法生成:

 

Class<?> classType =Customer.class;

Constructor cons =classType.getConstructor(new Class[]{});

Object obj = cons.newInstance(newObject[]{});

 

4. 若想通过类的带参数的构造方法生成对象,只能使用下面这一种方式:

 

Class<?> classType =Customer.class;

Constructor cons =classType.getConstructor(new Class[]{String.class, int.class});

Object obj = cons.newInstance(newObject[]{“hello”, 3});

 

5. Integer.TYPE返回的是int,而Integer.class返回的是Integer类所对应的Class对象。

 

Java SE Lesson10

1. 静态代理模式图示

 

2. Java注解(Annotation):

a) Override注解表示子类要重写(override)父类的对应方法。

b) Deprecated注解表示方法是不建议被使用的。

c) SuppressWarnings注解表示抑制警告。

 

2.    自定义注解:当注解中的属性名为value时,在对其赋值时可以不指定属性的名称而直接写上属性值即可;除了value以外的其他值都需要使用name=value这种赋值方式,即明确指定给谁赋值。

 

3.    当我们使用@interface关键字定义一个注解时,该注解隐含地继承了java.lang.annotation.Annotation接口;如果我们定义了一个接口,并且让该接口继承自Annotation,那么我们所定义的接口依然还是接口而不是注解;Annotation本身是接口而不是注解。可以与Enum类比。

 

 

4.    JUnit(3.8、4.x):Keep thebar green to keep the code clean.

 

5.    我的名言:没有反射,很多框架就不存在了。(NoReflection,No most frameworks)。

 

 

7. JUnit4的执行的一般流程:

a) 首先获得待测试类所对应的Class对象。

b) 然后通过该Class对象获得当前类中所有public方法所对应的Method数组。

c) 遍历该Method数组,取得每一个Method对象

d) 调用每个Method对象的isAnnotationPresent(Test.class)方法,判断该方法是否被Test注解所修饰。

e) 如果该方法返回true,那么调用method.invoke()方法去执行该方法,否则不执行。

 

8. 单元测试不是为了证明你是对的,而是证明你没有错误。

 

10.     WritingSecure Code(编写安全的代码):Input is evil。

 

 

 

Java SE Lesson 11

1.    所谓自定义异常,通常就是定义了一个继承自Exception类的子类,那么这个类就是一个自定义异常类。通常情况下,我们都会直接继承自Exception类,一般不会继承某个运行时的异常类。

 

2.    我们可以使用多个catch块来捕获异常,这时需要将父类型的catch块放到子类型的catch块之后,这样才能保证后续的catch可能被执行,否则子类型的catch将永远无法到达,Java编译器会报编译错误;如果多个catch块的异常类型是独立的(MyException, MyException2), 那么谁前谁后都是可以的。

 

 

3.    如果try块中存在return语句,那么首先也需要将finally块中的代码执行完毕,然后方法再返回。

 

4.    如果try块中存在System.exit(0)语句,那么就不会执行finally块中的代码,因为System.exit(0)会终止当前运行的Java虚拟机,程序会在虚拟机终止前结束执行。

 

5.    GUI(Graphical User Interface),图形用户界面。

 

6.    AWT(Abstract Window Toolkit),抽象窗口工具集,第一代的Java GUI组件,是重量级的。

 

 

7.      Swing,不依赖于底层细节,轻量级的组件。

 

 

 

Java SE Lesson 12

1. 事件-描述发生了什么的对象

事件源-事件的产生器

事件处理器-接收事件、解释事件并处理用户交互的方法

 

2. 当单击一个按钮时就会产生一个事件(ActionEvent),然后检查是否有与该按钮关联的事件处理器(实际上就是一个方法),如果没有,那么什么都不执行;如果有,就会将该事件传递给与该按钮关联的事件处理器方法,作为该方法的参数,之后该事件处理器方法就会自动得到调用,并且该方法可以使用传递过来的ActionEvent对象,进而获得事件发生时与该事件及事件源相关联的那些信息。

 

3. Java中的组件若想添加事件处理器,都会使用形如addXxxListener的方法来添加。

 

4. 作业:实现一个简单的计算器。Input is evil.

 

5. 观察者模式:

 

6. Swing。

7. 作业:

1) 阅读Observable类的源代码,理解Observable类与Observer接口之间的调用关系。

2) 编写一个程序,声明一个类,该类继承自Observable(因此该类是个主题角色),有一个int类型的变量,初始值为10,编写一个for循环,将该数字每次递减1,一直到0为止,每次变化时,都将该数字传递给它的观察者,观察者会打印出该数字;第二个观察者在该数字变为5之后开始打印该数字。

 

 

 

Java SE Lesson 13

1. 内部类(Inner Class),内部类共分为4种。

2. 静态内部类(static inner class):只能访问外部类的静态成员变量与静态方法,生成静态内部类对象的方式为:

OuterClass.InnerClass inner = newOuterClass.InnerClass();

 

3. 成员内部类(member inner class):可以访问外部类的静态与非静态的方法与成员变量。生成成员内部类对象的方式为:

OuterClass.InnerClass inner = new OuterClass().newInnerClass();

 

4. 若想在局部内部类中访问外部类的成员变量,语法为:OuterClass.this.a;

 

6.    局部内部类(Local Inner Class):定义在方法当中,只能访问方法中声明的final类型的变量。

 

7.    匿名内部类(Anonymous Inner Class):匿名内部类会隐式地继承一个父类或实现一个接口。

 

 

8.    所谓递归(Recursion),就是方法调用自身。对于递归来说,一定有一个出口,让递归结束,只有这样才能保证不出现死循环。

 

9.      作业:给定任意一个目录,以树形方式展现出该目录中的所有子目录和文件。另外,在展现的时候将目录排在上面,文件排在下面。每一层要加上缩进。

 

 

 

 

 

10. 异常(Exception)。

11. Java中的异常分为两大类:

a) Checked exception (非 RuntimeException)

b) Unchecked exception(RuntimeException)

12. Java中所有的异常类都会直接或间接地继承自Exception。

13. RuntimeException类也是直接继承自Exception类,它叫做运行时异常,Java中所有的运行时异常都会直接或间接地继承自RuntimeException

14. Java中凡是继承自Exception而不是继承自RuntimeException的类都是非运行时异常。

 

15. 异常处理的一般结构是:

 

try

{

}

catch(Exception e)

{

}

finally

{

}

无论程序是否出现异常,finally块中的代码都是会被执行的。

16. 对于非运行时异常(checkedexception),必须要对其进行处理,处理方式有两种:第一种是使用try.. catch…finally进行捕获;第二种是在调用该会产生异常的方法所在的方法声明throws Exception

17. 对于运行时异常(runtimeexception),我们可以不对其进行处理,也可以对其进行处理。推荐不对其进行处理。

18. NullPointerException是空指针异常,出现该异常的原因在于某个引用为null,但你却调用了它的某个方法。这时就会出现该异常。

 

 

 

Java SE Lesson 15

1. 一个类若想被序列化,则需要实现java.io.Serializable接口,该接口中没有定义任何方法,是一个标识性接口(Marker Interface),当一个类实现了该接口,就表示这个类的对象是可以序列化的。

2. 在序列化时,static变量是无法序列化的;如果A包含了对B的引用,那么在序列化A的时候也会将B一并地序列化;如果此时A可以序列化,B无法序列化,那么当序列化A的时候就会发生异常,这时就需要将对B的引用设为transient,该关键字表示变量不会被序列化。

 

3. 当我们在一个待序列化/反序列化的类中实现了以上两个private方法(方法声明要与上面的保持完全的一致),那么就允许我们以更加底层、更加细粒度的方式控制序列化/反序列化的过程。

 

4. Java中如果我们自己没有产生线程,那么系统就会给我们产生一个线程(主线程,main方法就在主线程上运行),我们的程序都是由线程来执行的。

 

6.    进程:执行中的程序(程序是静态的概念,进程是动态的概念)。

 

7.    线程的实现有两种方式,第一种方式是继承Thread类,然后重写run方法;第二种是实现Runnable接口,然后实现其run方法。

 

8.    将我们希望线程执行的代码放到run方法中,然后通过start方法来启动线程,start方法首先为线程的执行准备好系统资源,然后再去调用run方法。当某个类继承了Thread类之后,该类就叫做一个线程类。

 

9.    一个进程至少要包含一个线程。

 

10. 对于单核CPU来说,某一时刻只能有一个线程在执行(微观串行),从宏观角度来看,多个线程在同时执行(宏观并行)。

 

10. 对于双核或双核以上的CPU来说,可以真正做到微观并行。

 

1) Thread类也实现了Runnable接口,因此实现了Runnable接口中的run方法;

2) 当生成一个线程对象时,如果没有为其设定名字,那么线程对象的名字将使用如下形式:Thread-number,number将是自动增加的,并被所有的Thread对象所共享(因为它是static的成员变量)。

3) 当使用第一种方式来生成线程对象时,我们需要重写run方法,因为Thread类的run方法此时什么事情也不做。

 

 

4) 当使用第二种方式来生成线程对象时,我们需要实现Runnable接口的run方法,然后使用new Thread(new MyThread())(假如MyThread已经实现了Runnable接口)来生成线程对象,这时的线程对象的run方法就会调用MyThread类的run方法,这样我们自己编写的run方法就执行了。

 

11. 关于成员变量与局部变量:如果一个变量是成员变量,那么多个线程对同一个对象的成员变量进行操作时,他们对该成员变量是彼此影响的(也就是说一个线程对成员变量的改变会影响到另一个线程)。

 

12. 如果一个变量是局部变量,那么每个线程都会有一个该局部变量的拷贝,一个线程对该局部变量的改变不会影响到其他的线程。

 

13. 停止线程的方式:不能使用Thread类的stop方法来终止线程的执行。一般要设定一个变量,在run方法中是一个循环,循环每次检查该变量,如果满足条件则继续执行,否则跳出循环,线程结束。

 

14. 不能依靠线程的优先级来决定线程的执行顺序。

 

15. synchronized关键字:当synchronized关键字修饰一个方法的时候,该方法叫做同步方法。

 

16. Java中的每个对象都有一个锁(lock)或者叫做监视器(monitor),当访问某个对象的synchronized方法时,表示将该对象上锁,此时其他任何线程都无法再去访问该synchronized方法了,直到之前的那个线程执行方法完毕后(或者是抛出了异常),那么将该对象的锁释放掉,其他线程才有可能再去访问该synchronized方法。

 

17. 如果一个对象有多个synchronized方法,某一时刻某个线程已经进入到了某个synchronized方法,那么在该方法没有执行完毕前,其他线程是无法访问该对象的任何synchronized方法的。

 

 

 

 

 

 

Java SE Lesson 17

 

1. 对于单例模式(Singleton)来说,如果在getInstance()方法中生成Singleton实例则可能会产生同步问题,即可能会生成两个不同的对象。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

专题:

String 详解:

 

问题:

public class Test{
public static void changestr(String str){
str = "welcome";
}
public static void main(String []args)
{
String str = "1234";
changestr(str);
System.out.println(str);
}
}
输出结果为什么是 1234??

解答:

   这个主要涉及到String类型变量的不变性,private final char value[];String类中保存值得成员是这样定义的,所以在类存堆中new出一个String对象后该对象不能再改变。
  主函数中的str与changestr(Stringstr)中的str是两个不同的引用,当调用函数时,把主函数中str引用指向的对象赋值给changestr(String str)中的str,即是changestr(String str)中str与主函数中的str指向同一个String对象,当函数中给str赋值是,由于String类型变量的不变性所以不是去改变"1234" (String str ="1234";)这个对象而是去创建另一个新的对象“welcome”(str = "welcome";),而changestr(Stringstr)中的str这个引用指向它,而不是主函数中的str指向它,所以会出现这样的情况。
  对于String类型变量的赋值,遵循下面的规则,java中有String pool(我估计是由于String对象的不变性,所以java中有String pool)。
  java中有两种赋值方式,一种采用字面值方式的赋值,String s ="aaa"; 查找String pool中是否存在“aaa”这个对象,如果不存在,则在String pool 中创建一个"aaa"对象,然后将String pool中这个对象的地址返回给s这个引用,这样s会指向Stringpool 中"aaa"这个对象。如果Stringpool中已经有这个“aaa”对象时java虚拟机不会创建新的对象,而是将这个对象的地址直接返回。
  另一种方式是String s = new String("aaa"); 首先在String pool 中查找有没有这个对象,如果已经有了,则不再String pool中创建了,而是在堆中创建该对象,然后返回堆中该对象的地址。如果没有,则在String pool中创建该对象,并且在堆中也创建该对象,最后返回堆中该对象的地址给s。

 

ps:

在java中,说String是不可变的,可是为什么

假设String s=new String ("wo");String s1=newString("de");

s=s+s1;

System.out.println(s);结果为wode?

最佳答案

首先在栈中有个"s"变量指向堆中的"wo"对象...

栈中"s1"变量指向堆中的"de"对象

当执行到s = s + s1;

系统重新在堆中new一个更大的数组出来,然后将"wo"和"de"都复制进去,然后栈中的"s"指向这个新new出来的数组...

所谓的不可变是指:它没有在原数组“wo”上进行修改,而是新建了个更大数组进行扩展,也就是说,这时候堆里还是有“wo”

这个对象数组存在的,只不过这个时候"s"变量不在指向"wo"这个数组了,而是指向了新new出来的数组,这就是和StringBuffered的区别,

后者是在原数组上进行修改,改变了原数组的值,StringBuffered不是通过新new一个数组去复制,而是在原数组基础上进行扩展...再让

变量指向原数组....

 

 

 

 

 

 

 

 

IO:

练习:

import java.io.*;

class IOTest {
   
    public static void main(String[] args) throws Exception{
       
        /*String path ="D://zhoulai.java";*/
        /*File f = new File(path);*/
       
        /*FileOutputStream fos = newFileOutputStream(path);
       fos.write("www.qianxue.com".getBytes());
        fos.close();
       
        FileInputStream fis = newFileInputStream(path);
        byte[] buf = new byte[1000];
        int len = fis.read(buf);
        String str = new String(buf,0,len);
        System.out.println(str);
       
        String path2 ="E://accept.doc";
        File f = new File(path2);
        f.createNewFile();
       
       
        FileOutputStream fos1 = newFileOutputStream(path2);
        BufferedOutputStream bos = newBufferedOutputStream(fos1);
        DataOutputStream dos = newDataOutputStream(bos);
        dos.write(buf);
        dos.close();
       
        FileInputStream fis2 = newFileInputStream(path);
        BufferedInputStream bis = newBufferedInputStream(fis2);
        DataInputStream dis = newDataInputStream(bis);
        byte[] buf1 = new byte[1000];
        int len1 = dis.read(buf1);
        String str1 = new String(buf1,0,len1);
        System.out.println(str1);*/
       
       
       
       
        //一个char一个char的读取
        //InputStreamReader 的构造需要传入InputStream,而FileReader可以用File来构造.
        //BufferedReader in= newBufferedReader(new File("xx"));
        //BufferedReader in= newBufferedReader(new InputStreamReader("字节流的如:FileInputStream类型的"));
        //可以认为BufferedReader的效率要高于InputStreamReader的效率,但是BufferedReader不能提供字节流到字符流的转换,所以为了达到最高效率,可要考
        //虑在 BufferedReader 内包装InputStreamReader。例如:BufferedReader in= new BufferedReader(newInputStreamReader(System.in));
       
       
       
        /*String path ="E://accept.doc";
        File f = new File(path);
        FileReader fr = new FileReader(f);
        BufferedReader br = newBufferedReader(fr);
        //char ch= (char)fr.read();
        //System.out.println(ch);//读出了第一个char
        int i;
        while((i=br.read()) != -1) {
           System.out.print((char)i);   
        }
        br.close();*/
       
       
       
        //System.in 标准输入流,是InputStream类型的.
        /*InputStreamReader isr = newInputStreamReader(System.in);
    BufferedReader br2 = new BufferedReader(isr);
    String strLine;
    while((strLine = br2.readLine()) != null) {
        System.out.println(strLine);
    }
    br2.close();*/
    }

 

结构:

 

 

 

多线程:

 

一道Java线程面试题。3个线程顺序打印10次ABC.

2011-06-12 00:30

遇到一题,网上搜索一下,才知是流行已久的面试题。相信很多有心求职的同学都经常做流 行面试题备战各大公司面试吧。有点像应试备战。没做过这些题目练习的肯定要吃亏了。所 以很多公司为了避免走入应试误区也会采取一些除了这种客观笔试外的主观面试以考察应聘 者的真正解决问题的能力,以防止猜题、押宝。

题目描述:有三个线程名字分别是A、B、C,每个线程只能打印自己的名字,在屏幕上顺序打印 ABC,打印10次。不准使用线程的sleep()

 地址:http://hi.baidu.com/dapplehou/blog/item/14e62834ebe1bc235ab5f504.html

第一,我自己的一个解法:

public class SwitchStatus extends Thread {

    private static String currentThread = "A";

    private static byte[] lock = new byte[0];

    private String name = "";

    private int count = 10;

 

    public SwitchStatus(String name) {

        this.name = name;              

    }

 

    public void run() {

        while (count > 0) {

            synchronized (lock) {

                if (currentThread.equals(this.name)) {

                    System.out.print(name);

                    count--;

                    if (currentThread.equals("A")) {

                        currentThread = "B";

                    } else if (currentThread.equals("B")) {

                        currentThread = "C";

                    } else if (currentThread.equals("C")) {

                        currentThread = "A";

                        System.out.println();

                    }

                }

            }

        }

    }

 

    /**

     * @param args

     */

    public static void main(String[] args) {               

        (new SwitchStatus("A")).start();

        (new SwitchStatus("B")).start();

        (new SwitchStatus("C")).start();

    }

}

 

第二,网上看到一个不错的解法:

public class MyThread extends Thread{

    private static Object o = new Object();

    private static int count = 0;

    private char ID;

    private int id;

    private int num = 0;

    public MyThread(int id, char ID) {

        this.id = id;

        this.ID = ID;

    }

 

    public void run() {

        synchronized (o) {

            while (num < 10) {

                if (count % 3 == id) {

                    System.out.print(ID);

                    ++count;

                    ++num;

 

                    o.notifyAll();

 

                }

                else {

                    try {

                        o.wait();

                    } catch (InterruptedException e) {

                        e.printStackTrace();

                    }

                }

            }

        }

    }

    public static void main(String[] args) {

        (new MyThread(0, 'A')).start();

        (new MyThread(1, 'B')).start();

        (new MyThread(2, 'C')).start();

    }

}

这两种解法的思路是相似的。

  1. 对公共资源加锁,以阻塞其它线程。
  2. 用一个全局变量(3个线程都可访问的公共变量)控制状态 第一种解法的全局变量是:private static String currentThread = "A"; 第二种解法的全局变量是:private static int count = 0;配合count%3来控制状态。

对这道题来说,如果开动脑筋,好像有无穷无尽的解法。比如可以采用CyclicBarrier来进行 线程控制,关于CyclicBarrier的使用可参考http://hi.baidu.com/dapplehou/blog/item/0a4c65388143b72c96ddd814.html#sec-9

 

第三,下面,我使用CyclicBarrier来写一段这样的打印代码.

public class CycliBarrierTest implements Runnable {

    private static List list = new ArrayList(3);

    private CyclicBarrier barrier;

    private String name ="";

 

    public CycliBarrierTest(CyclicBarrier barrier,String name) {

        this.barrier = barrier;

        this.name = name;

    }

 

    public void run() {

        //do xxxx;

        try {

            for(int i=0;i<10;i++){                     

                list.add(name);

                this.barrier.await();//线程运行至此会检查是否其它线程都到齐了,没到齐就继续等待。到齐了就执行barrier的run函数体里的内容

            }

        } catch (Exception e) {

 

        }

    }

 

    /**

     * @param args

     */

    public static void main(String[] args) {

        //参数3代表3个线程都达到起跑线才开始一起继续往下执行

        CyclicBarrier barrier = new CyclicBarrier(3, new Runnable() {

                public void run() {

                    //do xxxx;                 

                    Collections.sort(list);

                    for(int i=0,n=list.size();i<n;i++){

                        System.out.print(list.get(i));

                    }

                    list.clear();

                    System.out.println();

                }

            });

        Thread t1 = new Thread(new CycliBarrierTest(barrier,"A"));        

        Thread t2 = new Thread(new CycliBarrierTest(barrier,"B"));

        Thread t3 = new Thread(new CycliBarrierTest(barrier,"C"));

        t1.start();

        t2.start();

        t3.start();

    }

 

}

 

第四,既然使用了java.util.concurrent包里的类,就不妨再使用这个包里的另一个类Semaphore. 即,用信号量作线程控制。

代码如下

public class SemaphoreThread extends Thread {

    private Semaphore current;

    private Semaphore next;

    public SemaphoreThread(String name, Semaphore current, Semaphore next) {

        super(name);

        this.current = current;

        this.next = next;

    }              

    public void run() {

        for (int i = 0; i < 10; i++) {

            try {

                current.acquire();

            } catch (InterruptedException e) {

                e.printStackTrace();

            }

            System.out.print(this.getName());

            next.release();

        }

    }      

 

    public static void main(String[] args) {

        Semaphore a = new Semaphore(1);

        Semaphore b = new Semaphore(0);

        Semaphore c = new Semaphore(0);

        new SemaphoreThread("A", a, b).start();

        new SemaphoreThread("B", b, c).start();

        new SemaphoreThread("C", c, a).start();

               

    }

}

 

第五,还有其它方法吗?当然有。这次,我就试着用一个阻塞队列再写一个打印abc的程序。

public class BlockingQ extends Thread {

        private static String currentThread = "A";

        private static BlockingQueue<String> blockingQ = new ArrayBlockingQueue<String>(

                        1);

        private String name = "";

        private int count = 10;

 

        public BlockingQ(String name) {

                this.name = name;

        }

 

        @Override

        public void run() {

            while (count > 0) {

                try {

                    blockingQ.put(name);

                } catch (InterruptedException e) {

                    // TODO Auto-generated catch block

                    e.printStackTrace();

                }

                if (currentThread.equals(this.name)) {

                    try {

                        System.out.print(blockingQ.take());

                    } catch (InterruptedException e) {

                        // TODO Auto-generated catch block

                        e.printStackTrace();

                    }                              

                    count--;

                    if (currentThread.equals("A")) {

                        currentThread = "B";

                    } else if (currentThread.equals("B")) {

                        currentThread = "C";

                    } else if (currentThread.equals("C")) {

                        currentThread = "A";

                        System.out.println();

                    }

                }else{

                    try {

                        blockingQ.take();

                    } catch (InterruptedException e) {

                        // TODO Auto-generated catch block

                        e.printStackTrace();

                    }

                }

                       

            }

        }

 

 

 

 

各种牛角尖

 

这是以前别人发的帖子,我整理了一下,都是一些很有趣的题目。


  from:火龙果


前言

大家先不要上机,先看看能不能得到正确的结果,请大家最好写上你所做的题目的相关知识点,这样大家都可以学习。
有兴趣的朋友可以篇号.题号,然后给出自己的想法。当然我想肯定有人做过这些题目了。

希望大家可以给出相关的想法,相关的考点,我已经整理了一份答案,到时候再贴出来。

第一篇

1.如果问大家“&”、“|”、“^”这三个是什么运算符?基会本上都会回答“位运算符”,但这样的回答只能得50分。大多数的Java程序员很可能不知道它还能充当其他的运算符——布尔逻辑运算符(前提是两边的数据类型为布尔类型)。

在 布尔逻辑运算符中这三个运算符充当着“布尔逻辑与”、“布尔逻辑或”和“布尔逻辑异或”的角色。前面两个把它们再复制一个放在一起就成了逻辑运算符。布尔 逻辑与(&)和布尔逻辑或(|)运算符的工作方式同逻辑与(&&)和逻辑或(||)的工作方式相同,布尔逻辑运算符的优先级别要 高于逻辑运算符,除此之外它们还有一点细微的差别,看一看下面的程序将会输出什么,就会明白了。

最后一个布尔逻辑异或(^)用得就更少了,可以采用关系运算符不等于(!=)来代替,在此就不深究了。

布尔逻辑运算符与逻辑运算符还有个区别,就是布尔逻辑运算符可以与赋值运算符(=)结合成布尔逻辑赋值运算符(&=、|=、^=),而逻辑运算符就没有这样的功能,可能它本身就有两个了吧,再结合“=”的话就变三个了,呵呵,太多了 :)

Java code

Java code

 

public class Test1 {

    public static void main(String[] args) {

       int m = 5, n = 5;

       if ((m != 5) && (n++ == 5)) {

       }

       System.out.println("a." + n);

       m = n = 5;

       if ((m != 5) & (n++ == 6)) {

       }

       System.out.println("b." + n);

       m = n = 5;

       if ((m == 5) || (n++ == 5)) {

       }

       System.out.println("c." + n);

       m = n = 5;

       if ((m == 5) | (n++ == 6)) {

       }

       System.out.println("d." + n);

    }

}

 



Output:


=====★==我==是==题==目==间==的==小==分==隔==符==★=====

2. 自动装箱的疑惑

JDK1.5中增加了自动拆装箱的语言特性,在基本类型和包装类型之间可以相互地转换和运算。大家也都知道Java中==运算符是比较两个对象间的引用是否相同。在自动拆装箱与“==”运算符之间也会产生一些奇怪的事情,看看下面的程序将会输出什么?

Java code

Java code

 

public class Test2 {

    public static void main(String[] args) {

       int k = 100;

       Integer int1 = k;

       Integer int2 = k;

       System.out.println("a." + (int1 == int2));

       k = 200;

       Integer int3 = k;

       Integer int4 = k;

       System.out.println("b." + (int3 == int4));

       char c = 'A';

       Character char1 = c;

       Character char2 = c;

       System.out.println("c." + (char1 == char2));

        c = '国';

       Character char3 = c;

       Character char4 = c;

       System.out.println("d." + (char3 == char4));

    }

}

 


Output:

=====★==我==是==题==目==间==的==小==分==隔==符==★=====

3. 奇怪的\u与0x

\u是Unicode字符的前缀,而0x是十六进制数值的前缀,能通用吗?下面的程序是否能如愿以偿地将Hello与World!分成两行输出呢?

Java code

Java code

 

public class Test3 {

    public static void main(String[] args) {

       /* 提示 \u000A 表示换行(LF),而 0x000A 表示什么呢? */

       char c = 0x000A;System.out.println("Hello" + c + "World!");

    }

}

 


Output:

=====★==我==是==题==目==间==的==小==分==隔==符==★=====

4.不可能发生的事

来个简单点的填空题哈,在空格处填上适当的数,让下面的程序能输出“Hello World!”。

Java code:

Java code

 

public class Test4 {

    public static void main(String[] args) {

       int num = _____________;

       if (num < 0 && num == Math.abs(num)){

           System.out.println("Hello World!");

       }

    }

}

 



填入:


=====★==我==是==题==目==间==的==小==分==隔==符==★=====

5,模棱两可的方法重载

invoke有两个重载的方法,一个是Object作为参数,另一个是int[]作为参数,看看下面的程序会输出什么?

Java code:

Java code

public class Test5 {

    public static void main(String[] args) {

       invoke(null);

    }

 

    private static void invoke(Object obj) {

       System.out.println("Object");

    }

 

    private static void invoke(int[]nums) {

       System.out.println("Arrays");

    }

}

 


Output:


=====★==我==是==题==目==间==的==小==分==隔==符==★=====

6,Number引起的计算错误

Number是众多数值类型的抽象父类,难道用它会引发计算错误?!看看下面的程序会输出什么?

Java code:

Java code

 

public class Test6 {

       public static void main(String[] args) {

           Number num = 12345 + 5432l;

            System.out.println(num.intValue());

       }

    }

 



Output:




第二篇

下面的几个程序会输出什么?先不要上机哦!!!
1.输出:
Java code:

Java code

 

public class Test3 {

    public static void main(String[] args) {

       Parrent p = new Parrent();

       Parrent c = new Child();

       

       System.out.println(p.getName());

       System.out.println(c.getName());

    }

}

class Parrent {

    public static String getName() {

       return "Parrent";

    }

}

class Child extends Parrent {

    public static String getName() {

       return "child";

    }

}

 



Output:


=====★==我==是==题==目==间==的==小==分==隔==符==★=====

2.输出:
Java code:

Java code

 

public   class   Test   {

       public static void main(String[] args) {

           for(int  i   =   0;  i   <=   10;  i++)

                Integer k   =   new   Integer(i);

           System.out.println( "Java  Puzzlers ");

        }

      }

 




Output:


=====★==我==是==题==目==间==的==小==分==隔==符==★=====

3
请补全 i 的声明(要求:i 不允许为 float、double、Float 和 Double 类型)让其能输出“Hello World”。
Java code:

Java code

 

public class Test {

    public static void main(String[] args) {

        fill here              ;

        if (i != i +0) {

            System.out.println("hello world");

        }

    }

}

 



填入:

=====★==我==是==题==目==间==的==小==分==隔==符==★=====

4.请问以下程序的输出结果是什么?

Java code:

Java code

 

import  java.math.BigInteger;

 

public   class   Test   {

    public   static   void   main(String[]   args)  {

       BigInteger   one   =   new   BigInteger( "1 ");

       BigInteger   two   =   new   BigInteger( "2 ");

       BigInteger   three   =   new   BigInteger( "3 ");

       BigInteger   sum   =   new   BigInteger( "0 ");

       sum.add(one);

       sum.add(two);

       sum.add(three);

       System.out.println(sum.toString());

  }

}

 



输出:

=====★==我==是==题==目==间==的==小==分==隔==符==★=====

5. 请将下面程序中的空格补全(要求见程序中)

  // 忽略 import 语句
Java code:  

Java code

 

public   class   Test   {

public   static   void   main(String[]   args)  {

   List <String>   list   =   new  ArrayList <String> ();

   list.add( "d ");

   list.add( "c ");

   list.add( "c ");

   list.add( "a ");

   list.add( "a ");

   list.add( "b ");

   list.add( "b ");

   list   =   removeDuplicate(list);

    //   输出的结果应是“d   c  a   b   ”

    for(String   str   :  list)   {

       System.out.print(str   +   "  ");

  }

}    

    /**

      *   方法功能:移除   List   中重复的元素,并保持原有的顺序

      */

        public   static   <T>   List <T>   removeDuplicate(List <T>   list)  {

             //   把空格处完善

          Return new ArrayList<T> (newLinkedHashSet<T>(list))___________________;

       }

}

 



填入:




第三篇
1. 请问以下程序会输出什么?
Java code:

Java code

 

public class Part {

    public static void main(String[] args) {

       int num = 32;

       System.out.println(num >>= 32);

    }

}

 



Output:

=====★==我==是==题==目==间==的==小==分==隔==符==★=====

2. 程序会输出什么呢?
Java code:

Java code

 

public class Part {

    public static void main(String[] args) {

       int j = 0;

       for (int i = 0; i < 100; i++) {

           j = j++;

       }

       System.out.println(j);

    }

}

 



Output:

=====★==我==是==题==目==间==的==小==分==隔==符==★=====

3. 程序输出什么?
Java code:

Java code

 

public class Part {

    public static void main(String[] args) {

       boolean b = true?false:true == true?false:true;

       System.out.println(b);

    }

}

 



Output:


=====★==我==是==题==目==间==的==小==分==隔==符==★=====

4.继续输出什么?
Java code:

Java code

 

public class Part {

    public static void main(String[] args) {

       List<String> list = new ArrayList<String> ();

       list.add("Happy");

       list.add("Birthday");

       list.add("to");

       list.add("you");

       

       for (Iterator i = list.iterator(); i.hasNext()){

           String s = i.next();

           System.out.println(s);

       }

    }

}

 



Output:

=====★==我==是==题==目==间==的==小==分==隔==符==★=====

5.输出神马?
Java code:

Java code

 

public class Part {

    public static void main(String[] args) {

       Queue<Integer> q = new PriorityQueue<Integer>(20, new Comparator<Integer>() {

           public int compare(Integer i1, Integer i2) {

                intresult = i1 % 2 - i2 % 2;

                if(result == 0) {

                    return i1 -i2;

                }

                else

                    return result;

           }

           

       });

       for (int i = 0; i < 20; i++) {

           q.add(i);

       }

       for (int i = 0; i < 20; i++) {

           System.out.println(q.poll());

       }

    }

}

 



Output:

=====★==我==是==题==目==间==的==小==分==隔==符==★=====

6. 请在以下程序段中的空白处补上最简洁的语句,在程序运行后会输出运行时的时间。

  显示格式为:yyyy-MM-dd HH:mm:ss
Java code:

Java code

 

  public class Part {

    public static void main(String[] args) {

       System.out.println(formatTime(System.currentTimeMillis()));

       

    }

 

    private static char[] formatTime(longcurrentTimeMillis) {

       return 这儿填什么;

    }

}

 




有兴趣的朋友可以篇号.题号,然后给出自己的想法。当然我想肯定有人做过这些题目了。

 

 

 

 

待续,,,,

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值