• 1. Java程序设计系列讲座-3 命名规范、异常处理和面向对象高级主题黄绍辉 厦门大学计算机科学系 E-mail: hsh@xmu.edu.cn
  • 2. Java命名规范
  • 3. 包的命名规范包的名称一般全部采用小写 包名的前缀一般是域名单词序列的逆序 实例 com.sun.eng com.apple.quicktime edu.cmu.cs.bovik.cheese
  • 4. 文件的命名规范必须与该文件中public类的类名同名 后缀必须是 .java
  • 5. 类/接口的命名规范类名一般是名词/名词词组:每个单词的首字母大写,其它字母小写 类名应当尽量简单,而且其含义能够尽量准确地刻画该类的含义 一般采用全称—尽量少用缩写词 (除非该缩写词被广泛使用) 实例 Clock Time ImageSprite
  • 6. 方法的命名规范方法名一般是 动词/动词性词组 首字母小写 中间单词的首字母大写,其它字母小写 尽量应用简单的、常用的单词 实例 run( ); getBackground( ); getTime( );
  • 7. 变量的命名规范变量名的首字母小写 中间单词的首字母大写,其它字母小写 变量名的首字母尽量不要用字符: _ 或 $ 变量名应当简短、有含义、且便于记忆 变量名常常由表示其所扮演的角色与数据类型组成 实例 int i; char c; double widthBox; Point startingPoint, centerPoint; Name loginName;
  • 8. 常量的命名规范常量名一般全大写,单词之间用下划线分隔 (“_”) 实例: static final int MIN_WIDTH = 4; static final int MAX_WIDTH = 999;
  • 9. 源文件编辑尽量不要用TAB排版 行数/每行的字符数不宜过多 缩排方式(Indentation) 多用空白符/行 友情提示:通常Java的开发环境都会提供源代码的格式化/重排功能,如果使用记事本编辑源代码,建议去下载一个叫astyle的源代码重排工具(DOS命令行工具)。UltraEdit有捆绑这个工具,并提供了GUI界面的调用方式。
  • 10. 文件组织源程序文件一般采用如下的组织顺序: 最开始一般是注释 package 和 import 语句 类和接口的定义
  • 11. 异常处理
  • 12. 异常和异常类型异常是程序运行时发生的错误。当异常发生时,常常导致程序崩溃,从而丢失尚未保存的数据。 用户输入非法是异常的主要来源,例如:
  • 13. 异常是可以捕捉的Java允许你自己去捕捉异常,从而避免程序崩溃。例如上例可以修改为:
  • 14. 异常的层次为了描述各种异常,Java派生了很多异常类:
  • 15. 异常的类型系统错误 包括LinkageError、VirtualMachineError等等,这种属于JVM错误,无法捕捉。 异常 包括ClassNotFoundException、IOException等等,这些异常可以被捕捉,而且一定要捕捉(受检异常),否则有编译错。 运行时异常 这些异常都是RuntimeException的派生类,如ArithmeticException、NullPointerException等等,这些异常可以被捕捉,但不一定要捕捉(非受检异常)。
  • 16. 理解异常处理异常处理的三个部分:声明异常(declaring an exception) ,抛出异常(throwing an exception)和捕捉异常(catching an exception )。
  • 17. 1. 声明异常(throws)声明myMethod方法会主动抛出IOException异常 public void myMethod() throws IOException 如果一个方法会抛出多个异常,用逗号隔开 public void myMethod() throws Exception1, Exception2, ..., ExceptionN 如果一个父类的方法没有声明为抛出异常,则子类覆盖此方法后,也不能声明为抛出异常。
  • 18. 2. 抛出异常(throw)异常的产生可以有两种:主动和被动。 被动的异常,典型的就是前面例子中的用户输入非法,这个时候会被动引发异常。 主动的异常,则是显式调用throw,直接抛出一个异常,例如: IllegalArgumentException ex = new IllegalArgumentException("Wrong Argument"); throw ex; throw new IllegalArgumentException("Wrong Argument");
  • 19. 3. 捕捉异常(try…catch)当一个异常被抛出之后,要这么捕捉: try { 可能引发异常的N条语句; } catch (Exception1 exVar1) { Exception1的N条处理语句; } catch (Exception2 exVar2) { Exception2的N条处理语句; } ... catch (ExceptionN exVar3) { ExceptionN的N条处理语句; } 一旦异常发生,try里面尚未执行的语句都将作废,直接转入catch处理流程,异常处理完毕后从try后面的语句开始执行; 注意catch是有顺序的,排前面的异常类型优先捕捉,一旦类型匹配,就进入相应的处理语句,并忽略余下的catch; 如果这一堆catch都没能捉到这个异常,那么这个异常会被继续向外抛出,直到被捉到为止或者程序崩溃为止。 一个忠告是,最后一个catch写成catch(Exception ex)最保险。
  • 20. 异常逐级抛出的例子图示的是main调用method1, method1调用 method2, method2调用method3, 然后method3有代码引发了异常。 此时捕捉异常的顺序是:method3、 method2、 method1、main。如果任何一次捕获成功,都可以消除异常,然后对应try之后的代码继续执行。否则程序就挂了。
  • 21. 获取异常的信息当捕获一个异常时,可以获取到异常的相关信息。一个比较有用的操作是打印异常的调用堆栈信息printStackTrace,通过堆栈你可以知道你的程序是怎么一步步死掉的。
  • 22. 一个异常的例子class Circle { private double radius = 1.0; public Circle(double newRadius) throws IllegalArgumentException { if (newRadius >= 0 ) radius = newRadius; else throw new IllegalArgumentException( "Radius cannot be negative"); } }
  • 23. (续) public class TestCircle { public static void main(String[] args) { try { Circle c1 = new Circle (5); System.out.println("c1 ok"); Circle c2 = new Circle (-5); System.out.println("c2 ok"); Circle c3 = new Circle (0); System.out.println("c3 ok"); } catch (IllegalArgumentException ex) { System.out.println(ex); } } }
  • 24. 再次抛出异常当程序捕捉到异常后,可以选择再次抛出此异常,以便外部函数捕捉处理。 try { statements; } catch (TheException ex) { perform operations before exits; throw ex; }
  • 25. finally放在try中的语句是不能保证都被执行的(如果发生异常的话),因此如果有一些代码需要在任何情况下(无论是否发生异常)都保证被执行到,可以用finally。 try { statements; } catch (TheException ex) { handling ex; } finally { finalStatements; }
  • 26. Finally的典型应用 1 public class FinallyDemo { 2 public static void main(String[] args) { 3 java.io.PrintWriter output = null; 4 5 try { 6 // Create a file 7 output = new java.io.Printwriter("text.txt"); 8 9 // Write formatted output to the file 10 output.println("Welcome to Java"); 11 } 12 catch (java.io.IOException ex) { 13 ex.printStackTrace(); 14 } 15 finally { 16 // Close the file 17 if (output != null) output.close(); 18 } 19 } 20 }
  • 27. 再来一个受检异常的例子Java在控制台下的输入: 注意要 import java.io.*; BufferedReader in=new BufferedReader(new InputStreamReader(System.in)); try{ String data = in.readLine(); }catch (IOException e){ } 这里如果没有try…catch,那么编译不能通过
  • 28. 再来一个非受检异常的例子字符串转成整数 这里假设s是String类型,并且由用户输入: int i; try { i = Integer.parseInt(s); }catch(Exception e){ e.printStackTrace(); } 这里不要try…catch也可以,但是当用户输入非法的时候,你的程序只好自求多福了…
  • 29. 关于异常的总结其实现在你只要知道如何捕捉一切异常就可以,其它的高级主题等你长大了就慢慢明白了…… try { //把可能引发异常的语句统统放在这里, //只要不超出try范围就可以。 }catch(Exception e){ //异常产生后,java会自动转向这里,如果 //你不知道此时该做点什么,放空好了。 }
  • 30. 何时采用异常异常会影响程序的执行效率,所以对于非受检异常,能不用就尽量不用。例如下面的代码就不合适: try { System.out.println(refVar.toString()); } catch (NullPointerException ex) { System.out.println("refVar is null"); } 上述代码能引发异常的也只有refVar为null时,因此写一个判断就足够了。当然如果引发异常的可能性很多,用多了if反而影响可读性,而且又不能保证if穷举了所有的出错可能性,这种情况下,用try…catch比较好。
  • 31. 面向对象高级主题
  • 32. 搞一个复杂一点的例子先热身我们想做一个类Circle表示平面直角坐标系上的一个圆(解析几何还记得吧...)。 然后我们想做一个求面积的成员函数。 我们还要假定所有的Circle的成员变量都是private的,所有的成员函数都是public的,下面开始动手设计这个类。。。
  • 33. 操作步骤 1先搭一个空架子总是没有问题的: class Circle{ }
  • 34. 操作步骤 2设计一下成员变量,这里三个足够了: class Circle{ private double r; //r是半径 private double x,y; //(x,y)是圆心坐标 }
  • 35. 操作步骤 3然后是构造函数,这里先搞两个: class Circle{ private double r; private double x,y; public Circle() { x=0; y=0; r=1; } public Circle(double x, double y, double r) { this.x=x; this.y=y; this.r=r; //一不小心用到了this,阿门,this是啥知道不? } }
  • 36. 操作步骤 4然后是面积函数: class Circle{ private double r; private double x,y; public Circle() { x=0; y=0; r=1; } public Circle(double x, double y, double r) { this.x=x; this.y=y; this.r=r; } public double getArea() { return (Math.PI*r*r); } }
  • 37. Eclipse测试程序综合一下以上的所有步骤: 先建一个工程,名字随意,再建一个类,名字叫Circle,然后把Circle的代码贴上; 再建一个类,名字随意,例如叫Test,勾上自动生成main函数的选项; 现在你的工程里应该有两个java源文件,两个类,其中一个是用来测试的类,所以它有main函数,Circle类由于没有main函数,所有它是不能运行的。因此启动运行的主类是Test。
  • 38. Test类的写法public class Test{ public static void main(String args[]) { Circle c1 = new Circle(); System.out.println(c1.getArea()); Circle c2 = new Circle(3.0,4.0,5.0); System.out.println(c2.getArea()); } }
  • 39. Circle的改进Circle类显然不完善,例如你在Test类里,如果想知道c1的x,y,r三个成员分别是多少,可能吗?如果你想在Test类里,随时修改c1的半径,可能吗? 答案显然不行,所以,Circle其实还有很多的成员函数需要添加。 这里就不演示了,自己动手试试。。。
  • 40. 研究一下对象的引用一个类的成员函数(static除外),是不是一定要new才能被使用呢?例如GUI编程中经常有这种语句: Container container = getContentPane(); container.add(new Button("hello button")); 这个container好像就没有new对吧?怎么就可以抓来用呢?难道随便get一下也能用? 其实这个container已经被new过了,只是你没有看见而已。get一下相当于做对象的引用。这么说好像很复杂,看一个例子:
  • 41. 对象的引用 Iclass A{ public int x; } public class Test{ public static void main(String args[]) { A a = new A(); a.x = 1; System.out.println("a.x="+a.x); A b = a; //注意这里b不是new出来的 b.x = 10; System.out.println("b.x="+b.x); System.out.println("a.x="+a.x); a.x = 100; System.out.println("a.x="+a.x); System.out.println("b.x="+b.x); } }这个例子的输出是:a.x=1 b.x=10 a.x=10 a.x=100 b.x=100
  • 42. 对象的引用 II总结一下,如果一个对象不是new出来的(例子中的b),而是直接用一个已经new出来的对象(例子中的a)给它赋值,那么这个对象b就叫做a的引用。 引用的对象之所以可以使用,不需要new,其实是因为它所指向的对象和赋值给它的对象是同一个!!!也就是它只是给原来的对象又起了一个名字而已。 顺便再提一次,对象作为函数参数的时候,实参都是通过引用传递的方式传给形参的。
  • 43. 再谈多态性
  • 44. 当继承发生的时候,多态性就来了运行时多态性是面向对象程序设计代码重用的一个最强大机制。 动态性的概念也可以被说成“一个接口,多个方法”。 Java实现运行时多态性的基础是动态方法调度,它是一种在运行时而不是在编译期调用重载方法的机制。 顺带提一下,静态的多态性就是函数重载。
  • 45. 方法覆盖当子类和超类定义了同样的函数时,就产生了方法覆盖,如: public class Circle extends GeometricObject { /** Override the toString method defined in GeometricObject */ public String toString() { return super.toString() + "\nradius is " + radius; } } 当覆盖发生时,在子类中,超类中的函数会被自动屏蔽;如果非要调用超类的函数,只能借助于super关键字。
  • 46. 覆盖和重载是不同的下图中的函数p,左边是覆盖,右边是重载 覆盖的特征:函数名相同,参数列表相同 重载的特征:函数名相同,参数列表不同
  • 47. 来一个例子class A{ protected int x; public void f() { x--; } } class B extends A{ int x; void f() { //覆盖了超类的f() this.x++; //这里用的是自己的x,也可以直接写x++ super.x = 100; //这里用的是超类继承来的x super.f(); //这里用的是超类继承来的f() } void f(int i) { //重载了继承来的函数f(),注意二者的参数列表不同 i++; } }
  • 48. 有个复杂点的例子class A { void fun() { System.out.println(“A”); } } class B extends A { void fun() { System.out.println(“B”); } } class C extends B { void fun() { System.out.println(“C”); } } class Test { public static void main(String[] args) { A a; B b = new B(); C c = new C();   a=b;  a.fun(); // 此处将输出B   a=c; a.fun(); // 此处将输出C } }
  • 49. 解释一下Java 的动态多态性这种机制遵循一个原则:当超类(父类)对象的引用变量引用子类对象时,被引用对象的类型而不是引用变量的类型决定了调用谁的成员方法; 当然,这个被调用的方法必须是在超类中定义过的,也就是说被子类覆盖的方法。你可能会问,如果这个方法没有被覆盖呢?Good question……
  • 50. 还有个例子class A { void fun() { System.out.println(“A”); } } class B extends A { void funB() { System.out.println(“B”); } } class C extends B { void funC() { System.out.println(“C”); } } class Test { public static void main(String[] args) { A a; B b = new B(); C c = new C();   a=b;  a.fun(); // 此处将输出A   a=c; a.fun(); // 此处将输出A } }
  • 51. 从编程角度来看抽象类
  • 52. 抽象类假设我们用GeometricObject这个类作为几何形状的基类,以便可以在GeometricObject的基础上派生出Circle类、Rectangle类等等具体的几何图形。 显然,GeometricObject这个类应该包含几何形状的一些共性:颜色、是否填充、创建日期、toString()函数、可以被求周长、可以被求面积…… 下面我们来设计这个类:
  • 53. 面积和周长的困惑颜色、是否填充、创建日期等函数不难写出相应的Java代码。但是这里有两个函数是没法写代码的,这就是面积和周长函数。这是因为面积和周长跟具体形状有关,在没有具体的形状之前,这两个属性没法计算。 现在的问题是,作为一个基类GeometricObject,如果没有设计getArea和getPerimeter函数,显然属于重大设计失误。但是这个函数又确实没法写,怎么办呢?Java说,好办,你可以把那两个函数做成抽象函数嘛。
  • 54. 抽象函数抽象函数是一种特殊函数,它只定义了函数原型,但是不需要实现这个函数。抽象函数用关键字abstract修饰。 包含抽象函数的类叫做抽象类,也必须用abstract修饰。 我们现在知道,抽象类只是一个半成品,所以Java中,抽象类不可以被new出来。
  • 55. GeometricObject类的部分代码 1 public abstract class GeometricObject { 2 private String color = "white"; 3 private boolean filled; 4 private java.util.Date dateCreated; 5 6 /** Construct a default geometric object */ 7 protected GeometricObject() { 8 dateCreated = new java.util.Date(); 9 } ... 43 /** Abstract method getArea */ 44 public abstract double getArea(); 45 46 /** Abstract method getPerimeter */ 47 public abstract double getPerimeter(); 48 }注意这两个抽象函数是没有函数体的。
  • 56. 抽象类的派生类刚才看到,抽象类有几个函数其实是没有实现的;于是Java规定,凡是抽象类的派生类,一定要完成父类的未竟事业。 例如从GeometricObject类派生两个类,一个叫做Circle,一个叫做Rectangle。那么这两个类都一定要覆盖(实现)getArea和getPerimeter函数。换句话说,这两个类可以没有其它成员,但是一定要实现这两个成员函数。
  • 57. Circle类的部分代码3 public class Circle extends GeometricObject { 4 private double radius; ... 23 /** Return area */ 24 public double getArea() { 25 return radius * radius * Math.PI; 26 } ... 33 /** Return perimeter */ 34 public double getPerimeter() { 35 return 2 * radius * Math.PI; 36 } ... 43 }注意这两个GeometricObject的抽象函数在这里一定要被实现。
  • 58. Rectangle类的部分代码 3 public class Rectangle extends GeometricObject { 4 private double width; 5 private double height; ... 35 /** Return area */ 36 public double getArea() { 37 return width * height; 38 } 39 40 /** Return perimeter */ 41 public double getPerimeter() { 42 return 2 * (width + height); 43 } 44 }注意这两个GeometricObject的抽象函数在这里一定要被实现。
  • 59. 抽象类小结 抽象函数只能在抽象类中出现,这些抽象函数在派生类中一定要被实现。 抽象类不能被new出来。 抽象类可以没有抽象函数,但是即便如此,它也不能被new出来。 即使父类不是抽象类,子类也可以定义成抽象类。 父类中的非抽象函数,可以被子类覆盖,并修改成抽象函数。 抽象类不能被new,但是抽象类是一个合法的数据类型。如: GeometricObject[] objects = new GeometricObject[10];
  • 60. 1 public class TestGeometricObject { 2 /** Main method */ 3 public static void main(String[] args) { 4 // Declare and initialize two geometric objects 5 GeometricObject geoObject1 = new Circle(5); 6 GeometricObject geoObject2 = new Rectangle(5, 3); 7 8 System.out.println("The two objects have the same area? " + 9 equalArea(geoObject1, geoObject2)); 10 11 // Display circle 12 displayGeometricObject(geoObject1); 13 14 // Display rectangle 15 displayGeometricObject(geoObject2); 16 } 17 18 /** A method for comparing the areas of two geometric objects */ 19 public static boolean equalArea(GeometricObject object1, 20 GeometricObject object2) { 21 return object1.getArea() == object2.getArea(); 22 } 23 24 /** A method for displaying a geometric object */ 25 public static void displayGeometricObject(GeometricObject object) { 26 System.out.println(); 27 System.out.println("The area is " + object.getArea()); 28 System.out.println("The perimeter is " + object.getPerimeter()); 29 } 30 } 一个测试程序
  • 61. 特殊抽象类:接口
  • 62. 接口-1当一个抽象类没有成员变量,并且其全部函数都被做成抽象函数时,Java会建议你使用interface这个关键字来替换class。所以,本质上,接口其实是一个抽象类,它的全部函数都是抽象函数并且没有成员变量(可以有静态常量)。 接口由于不带有成员变量,所以它特别适合用来描述一种通用的操作。例如同一个类的两个实例A、B比较大小这个操作,无论A、B是什么类的实例,你都可以定义A>B时,取正值;A=B时,取零;A
  • 63. 接口-2设计接口 public interface Comparable { public int compareTo(Object o); } 上面的interface约等于abstract class。 这里的函数compareTo是抽象函数,所以Comparable并不需要把这个函数具体实现(当然也没法实现)。
  • 64. 接口-3我们知道,抽象类在被继承时,派生类必须实现所有的抽象函数。类似的规定在接口上也是如此。 接口当然不能被继承,但是它可以被实现implements。当一个接口被实现时,所有它定义的函数都必须被实现(也就是新类必须覆盖这些函数)。 由于对象基本上都有可比性,其实很多Java类其实都实现了Comparable接口。
  • 65. 接口-4String类和Date类的部分源代码: 可见String的不同引用之间是可比的。注意下面的取值都是true,所以很大程度上,实现一个接口,跟继承一个类,没有什么区别。
  • 66. 接口-5实现一个接口,下面是一个可比较大小的矩形类: 1 public class ComparableRectangle extends Rectangle 2 implements Comparable { 3 /** Construct a ComparableRectangle with specified properties */ 4 public ComparableRectangle(double width, double height) { 5 super(width, height); 6 } 7 8 /** Implement the compareTo method defined in Comparable */ 9 public int compareTo(Object o) { 10 if (getArea() > ((ComparableRectangle)o).getArea()) 11 return 1; 12 else if (getArea() < ((ComparableRectangle)o).getArea()) 13 return -1; 14 else 15 return 0; 16 } 17 }
  • 67. 接口-6上例中,ComparableRectangle类继承了Rectangle类,并实现了Comparable接口。 在Java中,由于仅仅支持单一继承,所以每次只能extends一个类(这样就大大限制了OOP的功能);为了能够实现C++中多重继承的功能,Java允许你一次实现多个接口。
  • 68. 抽象类与接口小结
  • 69. 抽象类与接口-1成员变量构造函数成员方法抽象类无限制构造函数由子类调用,不允许被new出来无限制接口只能有静态常量(用 public static final修饰)没有构造函数,不允许被new出来所有方法都是抽象方法(用 public abstract修饰)
  • 70. 抽象类与接口-2这两个是相等的: Java只允许单一继承,但允许实现多接口 public class NewClass extends BaseClass implementes Interface1, ..., InterfaceN { ... } 接口之间倒是可以多继承,这叫子接口 public interface NewInterface extends Interface1, ..., InterfaceN { // constants and abstract methods }
  • 71. 抽象类与接口-3总而言之,Java所有的类有一个共同的基类Object,但是Java的所有接口并没有共同的祖先。 多重继承是OOP中比较重要的概念,Java用接口的方式实现了多重继承。
  • 72. 从概念设计角度来看抽象类
  • 73. 关于抽象类到目前为止,我们已经知道abstract class和interface其实都是抽象类。 OOP编程中,核心是“万物皆对象”。所以在Java里头,才会要求所有的函数和变量都必须被包含在某一个类(对象)中。 具体的类比较好理解,例如为了描述学生,我们可以建立Student这个类;可是,为什么Java还需要抽象类?
  • 74. 为什么需要抽象类?I在面向对象的概念中,所有的对象都是通过类来描述的,但是反过来却不是这样:并不是所有的类都是用来描述对象的,如果一个类中没有包含足够的信息来描述一个具体的对象,这样的类就是抽象类。 抽象类往往用来表征我们在对问题领域进行分析、设计中得出的抽象概念,是对一系列看上去不同,但是本质上相同的具体概念的抽象。 
  • 75. 为什么需要抽象类?II比如:圆、三角形、矩形这样一些具体概念,它们是不同的,但是它们又都属于形状这样一个概念,形状这个概念在问题领域是不存在的,它就是一个抽象概念。 正是因为抽象的概念在问题领域没有对应的具体概念,所以用以表征抽象概念的抽象类是不能够实例化的。(这就是为什么Java不准new出抽象类的对象)
  • 76. 为什么需要抽象类?III如果我们要设计一个Animal的类,用来表示动物;内含一个函数getType,表示得到这个动物的分类——可是这个分类目前是无法求的,因为我们的信息太少,所以,这个Animal只能设计成抽象类。 在Animal基础上,我们可以继承出一个类Cat,用来表示猫;也继承出一个类Dog,用来表示狗;显然,这两个阿猫阿狗类的getType函数体是可以实现的。
  • 77. 为什么需要抽象类?IVabstract class和interface在Java语言中都可以用来设计抽象类。 abstarct class在Java语言中体现了一种继承关系,要想使得继承关系合理,父类和派生类之间必须存在“is a”关系,即父类和派生类在概念本质上应该是相同的。 例如上一个例子,Cat和Dog都是一种动物,因此用Animal做父类是很自然的。此时Animal设计成abstract class在概念上也比较好接受。
  • 78. 为什么需要抽象类?IVinterface表示的是“like a”或者“has a”关系。我们用一个例子来表明,尽管都可以表示抽象类,但是abstract class并不是万能的。 例如我们设计一个类HaoJiao,用来描述动物的嚎叫。显然各种动物嚎法不同,所以这个类没法具体实现,因此只能设计成抽象类。可是,HaoJiao好继承吗?难道有更高级的HaoJiao? 再来看刚才那个类Animal,显然它应该会有HaoJiao的属性,但是Animal不能继承自HaoJiao(否则在概念上实在很难被接受)。于是我们只能将HaoJiao设计成interface,然后类Animal可以实现(implements)这个接口。
  • 79. 来个实际点的例子
  • 80. 创建自定义接口-1我们来设计一个“可吃”的接口。 public interface Edible { /** Describe how to eat */ public String howToEat(); } 再建立一个动物类 class Animal { }
  • 81. 创建自定义接口-2设计一个鸡类,显然鸡是一种动物,可吃。 class Chicken extends Animal implements Edible { int weight; public Chicken(int weight) { this.weight = weight; } public String howToEat() { return "Fry it"; } }
  • 82. 创建自定义接口-3再加点饭后水果 abstract class Fruit implements Edible { } class Apple extends Fruit { public String howToEat() { return "Make apple cider"; } } class Orange extends Fruit { public String howToEat() { return "Make orange juice"; } }
  • 83. 基本类型的包装类
  • 84. 用对象的方式处理基本类型OOP号称“Everything is an Object”,所以Java中唯一美中不足的,就是那些基本类型(char,int,float...)了。 为了弥补这个缺憾,Java为每一种基本类型设计了对应的包装类。功能上它们能够完全取代基本类型,当然,用起来要麻烦一点。
  • 85. 数值型包装类的构造函数可以直接从基本数值类型(或形如数值的字符串),作为参数去构造出一个对应的包装类。 例如: Double doubleObject = new Double(5.0); Double doubleObject = new Double("5.0"); Integer integerObject = new Integer(5); Integer integerObject = new Integer("5"); 在JDK1.5以上版本,你还可以这样偷懒一把: Double doubleObject = 5.0; Integer integerObject = 5;
  • 86. 数值型包装类的常量数值型包装类提供了最大值和最小值常量 MAX_VALUE 和MIN_VALUE,你可以从两个数得知该类型的取值范围。 例如: System.out.println("The maximum integer is " + Integer.MAX_VALUE); System.out.println("The minimum positive float is " + Float.MIN_VALUE); System.out.println("The maximum double precision floating-point number is " + Double.MAX_VALUE);
  • 87. 数值型包装类 => 基本类型可以使用包装类的doubleValue, floatValue, intValue, longValue, shortValue函数,从包装类取出对应的基本类型的值。 例如: long l = doubleObject.longValue(); //有截断 int i = integerObject.intValue();
  • 88. 数值包装类和字符串的转换数值包装类 => 字符串 double d = 5.9; Double doubleObject = new Double(d); String s = doubleObject.toString(); 字符串 => 数值包装类 Double doubleObject = Double.valueOf("1.4"); Integer integerObject = Integer.valueOf("12");
  • 89. 字符串 => 基本类型// These two methods are in the Byte class public static byte parseByte(String s) public static byte parseByte(String s, int radix) // These two methods are in the Short class public static short parseShort(String s) public static short parseShort(String s, int radix) // These two methods are in the Integer class public static int parseInt(String s) public static int parseInt(String s, int radix) // These two methods are in the Long class public static long parseLong(String s) public static long parseLong(String s, int radix) // These two methods are in the Float class public static float parseFloat(String s) public static float parseFloat(String s, int radix) // These two methods are in the Double class public static double parseDouble(String s) public static double parseDouble(String s, int radix)
  • 90. 题外话
  • 91. 可执行的Java程序 IJava可以编译成exe可执行文件吗?答案是:可以的。然而,坏消息是,就算你编译成exe文件,它仍然要在jre的环境中运行,而不能在没有安装jre的机器上独立运行。 说白了,Sun公司是不主张将Java编译成exe的,所以将Java编译成exe的工具不是Sun公司开发的。 至少有一个工具可以把Java搞成exe,那就是jsmooth(http://jsmooth.sourceforge.net/),有空你也试试?
  • 92. 可执行的Java程序 II应该还有很多同学愿意将Java编译成exe,因为至少,这样你的程序就可以双击运行,而不用敲:java 你的程序.class 其实,如果只是要双击运行你的程序,那至少有两种方法可以做到的。 一种是用快捷方式或者批处理文件,这个由于技术含量比较低,自己摸索一下。我们看另外一种。
  • 93. 可执行的Java程序 IIIJava其实有一个jar命令可以做到双击运行的,jar的作用是把一堆的class打包成一个文件,同时,当你双击它的时候,它可以自动查找你指定的主类,然后帮你启动主类开始运行——看看,这就是双击运行! jar命令的用法不算复杂,自己在命令行敲一下jar就有详细提示;其实你也可以用一些开发工具(例如Eclipse)的导出功能直接生成一个可执行的jar!
  • 94. THE END