什么是Java • Java是面向对象(Object-Oriented)程序 语言,具有更高的跨平台可能性 • 在今日,更多时候代表了软件开发的架构 • 开发者版本发表时是以Java DevelopmentKits名称发表,简称JDK • J2SE 5.0(Java 2 Platform Standard Edition5.0)时的JDK称为J2SE Development Kit 5.0
4.
什么是Java • J2SE 5.0(Java2 Platform Standard Edition5.0)时的JDK称为J2SE Development Kit 5.0 • 从JavaSE 6(Java Platform, Standard Edition6)开始的JDK6则称之为Java SE Development Kit 6 – 不再带有“2”这个号码,版本号6或1.6.0都使用 – 6是产品版本(productversion),而1.6.0是开 发者版本(developerversion)
第一个Java程序 • javac HelloJava.java •error: cannot read: HelloJava.java – javac工具程序找不到您指定的.java档案 • HelloJava.java:1: class HelloJava is public, should be declared in a file named HellJava.java – 类别名称与主档名不符
输出格式控制 控制字符 作用 反斜杠 ' 单引号' " 双引号" uxxxx 以16进位数指定Unicode字符输出 xxx 以8进位数指定Unicode字符输出 b 倒退一个字符 f 换页 n 换行 r 游标移至行首 t 跳格(一个Tab键) System.out.println("u0048u0065u006Cu006Cu006F");
逻辑、位运算 • 「且」(&&)、「或」(||)、「反相」(!) int number= 75; System.out.println((number > 70 && number < 80)); System.out.println((number > 80 || number < 75)); System.out.println(!(number > 80 || number < 75)); • &(AND)、|(OR)、^(XOR)与~(补 码) System.out.println("0 AND 0tt" + (0 & 0)); System.out.println("0 AND 1tt" + (0 & 1)); System.out.println("1 AND 0tt" + (1 & 0)); System.out.println("1 AND 1tt" + (1 & 1)); byte number = 0; System.out.println((int)(~number));
61.
逻辑、位运算 • 左移(<<)、右移(>>)、>>>运算符 int number= 1; System.out.println( "2的0次: " + number); number =number << 1; System.out.println("2的1次: " + number); number = number << 1; System.out.println("2的2次: " + number); number = number << 1; System.out.println("2的3次:" + number); 00000001 1 00000010 2 00000100 4 00001000 8
62.
递增、递减运算 • 递增、递减运算符 int i= 0; System.out.println(++i); System.out.println(--i); • 将递增或递减运算符撰写在变量之前或变 量之后 int i = 0; int number = 0; number = ++i; //相当於i = i + 1; number = i; System.out.println(number); number = --i; //相当於i = i - 1; number = i; System.out.println(number);
63.
递增、递减运算 • 将递增或递减运算符撰写在变量之前或变 量之后 int i = 0; int number = 0; number = i++; //相当於number = i; i = i + 1; System.out.println(number); number = i--; //相当于number = i; i = i - 1; System.out.println(number);
64.
递增、递减运算 指定运算符 范 例 结 果 += a += b a=a+b -= a -= b a=a-b *= a *= b a=a*b /= a /= b a=a/b %= a %= b a=a%b &= a &= b a=a&b |= a |= b a=a|b ^= a ^= b a=a^b <<= a <<= b a = a << b >>= a >>= b a = a >> b
使用对象 • 想写一个程序取得现在的系统时间,您只 要产生一个java.util.Date工具就可以了 • Date实际上如何向系统取得时间,则无需 您来操心 Date date = new Date(); System.out.println(date.toString()); Tue May 03 16:06:46 GMT+08:00 2005
使用正则表示式 • 几个常用的字符比对符号 方 法 说 明 . 符合任一字符 d 符合0到9任一个数字字符 D 符合0-9以外的字符 s 符合't'、'n'、'x0B'、'f'、'r'等空格符 w 符合a到z、A到Z、0到9等字符,也就是数字或是字母都符合 W 符合a到z、A到Z、0到9等之外的字符,也就是除数字与字母外 都符合
类别成员(Classmember) class MethodDemo { private int data = 10; public void scopeDemo() { // void表示没有传回值 int data = 100; } public int getData() { return data; } public void setData(int data) { // void表示没有传回值 data = data; //这样写是没用的 //写下面这个才有用 // this.data = data; } }
建构方法(Constructor) • 建构方法是与类别名称相同的公开方法成 员,且没有传回值 public class SafeArray { // .. public SafeArray() { //建构方法 // .... } public SafeArray(参数列) {//建构方法 // .... } }
157.
建构方法(Constructor) public class SafeArray{ private int[] arr; public SafeArray() { this(10); //预设10个元素 } public SafeArray(int length) { arr = new int[length]; } … }
关于static • 可以宣告方法成员为"static"方法,又称 「静态方法」 public class Ball { ... public static double toRadian(double angle) { return 3.14159 / 180 * angle; } } System.out.println("角度90等于径度" + Ball.toRadian (90));
165.
关于static •静态方法中不会有this参考名称 • 静态方法中不允许使用非静态成员 non-static variable test cannot be referenced from a static context • 在静态方法中不能呼叫非静态方法 non-static method showHello() cannot be referenced from a static context
不定长度自变量 • J2SE5.0之后开始支持「不定长度自变量」 (Variable-lengthArgument) public static int sum(int... nums) { //使用...宣告参数 int sum = 0; for(int num : nums) { sum += num; } return sum; } • 实际上nums是一个数组
173.
不定长度自变量 • 宣告的参数必须设定在参数列的最后一 个,下面的方式是合法的 public void someMethod(int arg1, int arg2, int... varargs) { // .... } • 下面的方式是不合法的 public void someMethod(int... varargs, int arg1, int arg2) { // .... }
递归方法 • 在方法中呼叫自身同名方法,而呼叫者本 身会先被置入内存「堆栈」(Stack)中 • 堆栈是一种「先进后出」(First in, lastout)的数据结构 private static int gcd(int m, int n) { if(n == 0) return m; else return gcd(n, m % n); }
被保护的(protected)成员 public class Rectangle{ //受保护的member protected int x; protected int y; protected int width; protected int height; … } public class CubicextendsRectangle { … public int getVolumn() { //可以直接使用父类别中的width、height成员 return length*width*height; } }
重新定义(Override)方法 public class SimpleArray{ protected int[] array; public SimpleArray(int i) { array = new int[i]; } public void setElement(int i, int data) { array[i] = data; } .... } public class SafeArrayextends SimpleArray { … //重新定义setElement() public void setElement(int i, int data) { if(i < array.length) super.setElement(i, data); } .... }
重新定义(Override)方法 • 您可以增大父类别中的方法权限,但不可 以缩小父类别的方法权限 – 若原来成员是"public"的话,您不可以在父类别 中重新定义它为"private"或"protected" public class SafeArray extends SimpleArray { //不可以缩小父类别中同名方法的权限 private void setElement(int i, int data) { .... } } setElement(int,int) in SafeArray cannot override setElement(int,in t) in SimpleArray; attempting to assign weaker accessprivileges; was publicprivate void setElement(int i, int data) {^1 error
192.
重新定义(Override)方法 • 从J2SE5.0开始在重新定义方法时,您可以 重新定义返回值的型态 public class Bird { protected String name; public Bird(String name) { this.name = name; } public Bird getCopied { return new Bird(name); } }
193.
重新定义(Override)方法 • 重新定义的返回值型态必须是父类别中同一方法 返回型态的子类别 public class Chicken extends Bird { protected String crest; public Chicken(String name, String crest) { super(name); this.crest = crest; } //重新定义返回值型态为Chicken publicChicken getCopied() { return new Chicken(name, crest); } } • 无法重新定义static方法
toString()、equals()、hashCode() public boolean equals(Objectother) { if (this == other) return true; if (!(other instanceof Cat)) return false; final Cat cat = (Cat) other; if (!getName().equals(cat.getName())) return false; if (!getBirthday().equals(cat.getBirthday())) return false; return true; } public int hashCode() { int result = getName().hashCode(); result = 29 * result + getBirthday().hashCode(); return result; }
198.
clone()方法 • 如何复制对象本身 • 最基本的作法:实作java.lang.Cloneable界 面(Interface) public class PointimplementsCloneable { //要实作Cloneable … public Object clone() throws CloneNotSupportedException { //呼叫父类别的clone()来进行复制 return super.clone(); } }
199.
clone()方法 public class TableimplementsCloneable{ //要实作Cloneable private Point center; // … public Object clone () throws CloneNotSupportedException { //呼叫父类的clone()来复制 Table table = (Table) super.clone(); if(this.center != null) { //复制Point类型的数据成员 table.center = (Point) center.clone(); } return table; } }
成员内部类别、区域内部类别 • 被宣告为static的内部类别,事实上也可以 看作是另一种名称空间的管理方式 public class Outer { public static class Inner { .... } .... } Outer.Inner inner = new Outer.Inner();
设定套件(package) • 「完全描述」(Fullyqualified)名称 –完整的指出「套件加类别」名称 onlyfun.caterpillar.Point2D p1 = new onlyfun.caterpillar.Point2D(10, 20); • 最后编译完成的.class档案必须放在onlyfun 目录的caterpillar目录下 bad class file: .Point2D.classclass file contains wrong class: onlyfun.caterpillar.Point2DPlease remove or make sure it appears in the correct subdirectory of the classpath. Point2D p1 = new Point2D(10, 20); ^1 error
230.
import的意义 • 您可以使用"import"关键词,告知编译程序 您所要使用的类别是位于哪一个套件 import onlyfun.caterpillar.Point2D; public class Point2DDemo2 { public static void main(String[] args) { Point2D p1 = new Point2D(10, 20); System.out.printf("p1: (x, y) = (%d, %d)%n", p1.getX(), p1.getY()); } }
231.
import的意义 • 使用"import"指定时,可于套件指定加上'*' importonlyfun.caterpillar.*; public class Point2DDemo3 { public static void main(String[] args) { Point2D p1 = new Point2D(10, 20); System.out.printf("p1: (x, y) = (%d, %d)%n", p1.getX(), p1.getY()); } }
232.
import的意义 • 可能出现以下的错误讯息 badclass file: .Point2D.java file does not contain class Point2D Please remove or make sure it appears in the correct subdirectory of the classpath. • 将原始码与编译完成的档案放在一起并不 是一个好的管理方式 javac -d ./classes ./src/*.java • 指定Classpath的方式如下执行程序 java -cp ./classes Point2DDemo3
233.
import的意义 • 同名冲突 importjava.util.Arrays; import onlyfun.caterpillar.Arrays; public class SomeClass { .... } java.util.Arrays is already defined in a single-type import import onlyfun.caterpillar.Arrays; ^1 error
234.
public与套件 • 没有被宣告为“public”的类别只能被同一个套件中 的类别之实例呼叫使用 Point2DDemo.java:3: onlyfun.caterpillar.Point2D is not public in onlyfun.caterpillar; cannot be accessed from outside package onlyfun.caterpillar.Point2D p1 = new • 类别成员也可以宣告为"public",宣告为"public" 的类别成员可以被其它对象呼叫使用 • 如果宣告类别时不使用"public"、"protected"或 "private"设定权限,则预设为「套件存取范围」
public与套件 • 定义一个类别,但没有定义建构方法时, 编译程序会自动帮您产生一个预设建构方 法 package onlyfun.caterpillar; public class Test { .... } package onlyfun.caterpillar; public class Test { public Test() { } .... }
238.
public与套件 • 如果您自行定义建构方法,则编译程序就 不会帮您加上预设建构方法 package onlyfun.caterpillar; public class Test { public Test(int i) { ... } .... } • 在建构时,就必须指明使用哪个建构方法
239.
public与套件 • 建议即使没有用到,在定义自己的建构方法的同 时,也加上个没有参数的建构方法 package onlyfun.caterpillar; public class Test { public Test() { //即使没用到,也先建立一个空的建构方法 } public Test(int i) { ... } .... } • 没有使用super()指定要使用父类别的哪个建构方 法,则预设会寻找父类别中无参数的建构方法
240.
public与套件 • 预设建构方法的访问权限是跟随着类别的 访问权限而设定 package onlyfun.caterpillar; public class Test {} • 由于类别宣告为public,所以预设建构方法 访问权限為public
241.
public与套件 • 如果是以下的话 packageonlyfun.caterpillar; class Test {} • 则预设建构方法访问权限为套件访问权 限,也就是编译程序会自动为您扩展为 package onlyfun.caterpillar; class Test { Test() { } }
242.
public与套件 存取修饰 同一类别 同一套件 子类别 全局 private OK (default) OK OK protected OK OK OK public OK OK OK OK
受检例外、执行时期例外 • 如果您不在程序中处理的话,例如将 IOException的"catch"区块拿掉 CheckedExceptionDemo.java:9: unreported exception java.io.IOException; must be caught or declared to be thrown
252.
受检例外、执行时期例外 try { BufferedReader buf = new BufferedReader( new InputStreamReader(System.in)); System.out.print("请输入整數: "); int input = Integer.parseInt(buf.readLine()); System.out.println("input x 10 = " + (input*10)); } catch(IOException e) { // Checked Exception System.out.println("I/O错誤"); } catch(NumberFormatException e) { // Runtime Exception System.out.println("输入必须为整數"); }
常数设置 • 可使用接口来定义操作时所需的共享常数 publicinterface ActionConstants { public static final int TURN_LEFT = 1; public static final int TURN_RIGHT = 2; public static final int SHOT = 3; }
264.
常数设置 public void someMethod(){ .... doAction(ActionConstants.TURN_RIGHT); .... } public void doAction(int action) { switch(action) { case ActionConstants.TURN_LEFT: System.out.println("向左转"); break; case ActionConstants.TURN_RIGHT: System.out.println("向右转"); break; case ActionConstants.SHOOT: System.out.println("射击"); break; } }
265.
常数设置 • 使用类别来宣告的话 public classCommandTool { public static final String ADMIN = "onlyfun.caterpillar.admin"; public static final String DEVELOPER = "onlyfun.caterpillar.developer"; public void someMethod() { // .... } } • 如果常数只是在类别内部使用的话,就宣 告其为“private”或是“protected”就可以了 – 宣告为类别外可取用的常数,通常是与类别功 能相依的常数
列举型态入门 public class EnumDemo{ public static void main(String[] args) { doAction(Action.TURN_RIGHT); } public static void doAction(Action action) { switch(action) { case TURN_LEFT: System.out.println("向左轉"); break; case TURN_RIGHT: System.out.println("向右轉"); break; case SHOOT: System.out.println("射擊"); break; } } }
限制泛型可用类型 • 一并使用"extends"指定这个型态持有者实 例化时,实例化的对象必须是扩充自某个 类型或实作某接口 import java.util.List; public class ListGenericFoo<T extends List> { private T[] fooArray; public void setFooArray(T[] fooArray) { this.fooArray = fooArray; } public T[] getFooArray() { return fooArray; } }
295.
限制泛型可用类型 • 在限定持有者时,无论是要限定的对象是 接口或类别,都是使用"extends"关键词 ListGenericFoo<LinkedList> foo1 = new ListGenericFoo<LinkedList>(); ListGenericFoo<ArrayList> foo2 = new ListGenericFoo<ArrayList>();
296.
限制泛型可用类型 • 如果不是实作List的类别,编译时就会发生 错误 ListGenericFoo<HashMap> foo3 = new ListGenericFoo<HashMap>(); type parameter java.util.HashMap is not within its bound ListGenericFoo<HashMap> foo3 = new ListGenericFoo<HashMap>();
DataInputStream、DataOutputStream • 提供一些对Java基本数据型态写入的方法 DataOutputStream dataOutputStream = new DataOutputStream( new FileOutputStream(args[0])); for(Member member : members) { //写入UTF字符串 dataOutputStream.writeUTF(member.getName()); //写入int资料 dataOutputStream.writeInt(member.getAge()); } //出清所有数据至目的地 dataOutputStream.flush(); //关闭串流 dataOutputStream.close();
350.
DataInputStream、DataOutputStream DataInputStream dataInputStream = new DataInputStream( new FileInputStream(args[0])); //读出数据并还原为对象 for(int i = 0; i < members.length; i++) { //读出UTF字符串 String name = dataInputStream.readUTF(); //读出int资料 int score = dataInputStream.readInt(); members[i] = new Member(name, score); } //关闭串流 dataInputStream.close();
351.
ObjectInputStream、ObjectOutputStream • 要直接储存对象,定义该对象的类别必须 实作java.io.Serializable界面 public class User implements Serializable { private static final long serialVersionUID = 1L; … } • serialVersionUID代表了可串行化对象版本 • 从档案读回对象时两个对象的 serialVersionUID不相同的话,就会丢出 java.io.InvalidClassException
限定Override父类方法@Override • 对编译程序说明某个方法必须是重新定义 父类别中的方法 public class CustomClass { @Override public StringToString() { return "customObject"; } } CustomClass.java:4: method does not override a method from its superclass @Override ^1 error
标示方法為Deprecated @Deprectated • 对编译程序说明某个方法已经不建议使用 public class Something { @Deprecated public Something getSomething() { return new Something(); } } Something some = new Something(); //呼叫被@Deprecated标示的方法 some.getSomething(); javac -Xlint:deprecation -d . SomethingDemo.java SomethingDemo.java:6: warning: [deprecation] getSomething() in onlyfun.caterpillar.Something has been deprecated some.getSomething(); ^1 warning
抑制编译程序警讯@SuppressWarnings •对编译程序说明某个方法中若有警示讯 息,则加以抑制 import java.util.*; public class SomeClass { public void doSomething() { Map map = new HashMap(); map.put("some", "thing"); } } Note: SomeClass.java uses unchecked or unsafe operations. Note: Recompile with -Xlint:unchecked for details. javac-Xlint:unchecked -d . SomeClass.java SomeClass.java:8: warning: [unchecked] unchecked call to put(K,V) as a member of the raw type java.util.Map map.put("some", "thing"); ^1 warning
465.
抑制编译程序警讯@SuppressWarnings import java.util.*; public class SomeClass2 { @SuppressWarnings(value={"unchecked"}) public void doSomething() { Map map = new HashMap(); map.put("some", "thing"); } } @SuppressWarnings(value={"unchecked", "deprecation"})
466.
自定义Annotation型态 • 定义Marker Annotation,也就是Annotation 名称本身即提供信息 • 对于程序分析工具来说,主要是检查是否 有MarkerAnnotation的出现,并作出对应的 动作 public@interface Debug {} public class SomeObject { @Debug public void doSomething() { // .... } }
467.
自定义Annotation型态 • Single-value annotation public@interface UnitTest { String value(); } public class MathTool { @UnitTest("GCD") public static int gcdOf(int num1, int num2) { // .... } }
自定义Annotation型态 public @interface Process{ public enum Current {NONE, REQUIRE, ANALYSIS, DESIGN, SYSTEM}; Current current() default Current.NONE; String tester(); boolean ok(); } public class Application { @Process( current =Process.Current.ANALYSIS, tester = "Justin Lin", ok = true ) public void doSomething() { // .... } }
自定义Annotation型态 • 定义Annotation型态时也可以使用套件机制 来管理类别 import onlyfun.caterpillar.Debug; public class Test { @Debug public void doTest() { } } public class Test { @onlyfun.caterpillar.Debug public void doTest() { } }
限定annotation使用对象@Target • 尝试将MethodAnnotation标示于类别之上 @onlyfun.caterpillar.MethodAnnotation public class SomeoneClass { public void doSomething() { // .... } } SomeObject.java:1: annotation type not applicable to this kind of declaration @onlyfun.caterpillar.MethodAnnotation^1 error
使用Date • 取得系统的时间,可以使用 System.currentTimeMillis()方法 public class CurrentTime { public static void main(String[] args) { System.out.println("现在时间" + System.currentTimeMillis()); } } • 从1970年1月1日0时0分0秒开始,到程序 执行取得系统时间为止所经过的毫秒数
487.
使用Date Date date =new Date(); System.out.println("现在时间" + date.toString()); System.out.println("自1970/1/1至今的毫秒数" + date.getTime()); 现在时间Mon Jun 06 22:03:52 GMT+08:00 2005 自1970/1/1至今的毫秒数1118066632890
488.
使用Date • 对日期时间作格式设定,则可以使用 java.text.DateFormat来作格式化 Date date = new Date(); DateFormat dateFormat = new SimpleDateFormat("EE-MM-dd-yyyy"); System.out.println(dateFormat.format(date)); 星期一-06-06-2005
489.
使用Date • 直接使用DateFormat上的静态 getDateTimeInstance()方法来指定格式 Date date = new Date(); //简短信息格式 DateFormat shortFormat = DateFormat.getDateTimeInstance( DateFormat.SHORT, DateFormat.SHORT); //中等信息格式 DateFormat mediumFormat = DateFormat.getDateTimeInstance( DateFormat.MEDIUM, DateFormat.MEDIUM); //长信息格式 DateFormat longFormat = DateFormat.getDateTimeInstance( DateFormat.LONG, DateFormat.LONG);
格式化讯息 String message ="Hello! {0}! This is your first {1}!"; Object[] params = new Object[] {"caterpillar", "Java"}; MessageFormat formatter = new MessageFormat(message); //显示格式化后的讯息 System.out.println(formatter.format(params));
510.
格式化讯息 onlyfun.caterpillar.greeting=Hello! {0}! Thisis your first {1}! //绑定messages.properties ResourceBundle resource = ResourceBundle.getBundle("messages2"); String message = resource.getString( "onlyfun.caterpillar.greeting"); Object[] params = new Object[] {args[0], args[1]}; MessageFormat formatter = new MessageFormat(message); //显示格式化后的讯息 System.out.println(formatter.format(params));