510 likes | 723 Views
Java 面向对象编程. 计算中心 张岩峰 zhangyf@cc.neu.edu.cn http://cloudgroup.neu.edu.cn/course/java/. 从 autoboxing 、 unboxing 认识 对象 关 于 对象 自动装箱、拆箱 封装 定义类别( Class ) 关于方法. 第 3 章 Java面向对象编程(上). 使用对象. 想写一个程序取得现在的系统时间,您只要产生一个 java.util.Date 工具就可以了 Date 实际上如何向系统取得时间,则无需您来操心.
E N D
Java面向对象编程 计算中心 张岩峰 zhangyf@cc.neu.edu.cn http://cloudgroup.neu.edu.cn/course/java/
从autoboxing、unboxing认识对象 关于对象 自动装箱、拆箱 封装 定义类别(Class) 关于方法 第3章Java面向对象编程(上)
使用对象 • 想写一个程序取得现在的系统时间,您只要产生一个java.util.Date工具就可以了 • Date实际上如何向系统取得时间,则无需您来操心 Date date = new Date(); System.out.println(date.toString()); Tue May 03 16:06:46 GMT+08:00 2005
使用对象 • 字符串就是对象,是java.lang.String类别的一个实例 String text = "Have a nice day!! :)"; System.out.println("原文:" + text); //传回全为大写的字符串内容 System.out.println("大写:" + text.toUpperCase()); //转回全为小写的字符串内容 System.out.println("小写:" + text.toLowerCase()); //计算字符串长度 System.out.println("长度:" + text.length()); //传回取代文字后的字符串 System.out.println("取代:" + text.replaceAll("nice", "good")); //传回指定位置后的子字符串 System.out.println("子字符串:" + text.substring(5));
使用对象 • 简单的用户登入程序 System.out.print("使用者名称:"); String username = scanner.next(); System.out.print("用户密码:"); String password = scanner.next(); if("caterpillar".equals(username) && "1975".equals(password)) { System.out.println("秘密信息在此!"); } else { System.out.println(username + "您好,输入的登入数据有误,请重新输入!"); }
包裹(Wrap)基本型态 • Long、Integer、Double、Float、Boolean等类别是所谓的Wrapper类别 • 主要目的,就是让您提供一个对象实例作为「壳」,将基本型态包到这个对象之中 • 如此您就可以操作这个对象,就好像您将基本型态当作对象一样操作
包裹(Wrap)基本型态 int data1 = 10; int data2 = 20; //使用Integer来包里int资料 Integer data1Wrapper = new Integer(data1); Integer data2Wrapper = new Integer(data2); //直接除以3 System.out.println(data1 / 3); //转为double值再除以3 System.out.println(data1Wrapper.doubleValue() / 3); //进行两个值的比较 System.out.println(data1Wrapper.compareTo(data2Wrapper));
自动装箱、拆箱 • 在J2SE5.0之前,要如下才能将int包装为一个Integer物件 • 在J2SE5.0之后提供了自动装箱的功能 Integer integer = new Integer(10); Integer integer = 10;
自动装箱、拆箱 Integer data1 = 10; Integer data2 = 20; //转为double值再除以3 System.out.println(data1.doubleValue() / 3); //进行两个值的比较 System.out.println(data1.compareTo(data2));
自动装箱、拆箱 • 自动装箱运用的方法还可以如下: • 更一般化的java.lang.Number类别自动装箱 int i = 10; Integer integer = i; Number number = 3.14f;
自动装箱、拆箱 • 自动拆箱(unboxing) • 在运算时,也可以进行自动装箱与拆箱 Integer fooInteger = 10; int fooPrimitive = fooInteger; Integer i = 10; System.out.println(i + 10); System.out.println(i++); Boolean boo = true; System.out.println(boo && false);
小心使用boxing • 自动装箱与拆箱的功能是编译程序来帮忙 • 自动装箱与拆箱的功能是所谓的「编译程序蜜糖」(Compilersugar) Integer i = 100; Integer i = new Integer(100); Integer i = null; int j = i; Integer i = null; int j = i.intValue(); NullPointerException
小心使用boxing Integer i1 = 100; Integer i2 = 100; if (i1 == i2) System.out.println("i1 == i2"); else System.out.println("i1 != i2"); 显示"i1 == i2" Integer i1 = 200; Integer i2 = 200; if (i1 == i2) System.out.println("i1 == i2"); else System.out.println("i1 != i2"); 显示"i1 != i2"
小心使用boxing • ‘==’也用于判断两个对象参考名称是否参考至同一个对象 • 在自动装箱时对于值从-128到127之间的值,它们被装箱为Integer对象后,会存在内存之中被重用 Integer i1 = 200; Integer i2 = 200; if (i1.equals(i2)) System.out.println("i1 == i2"); else System.out.println("i1 != i2");
以对象思考问题 有一个帐户,帐户中有存款余额,您可以对帐户进行存款与提款的动作,并可以查询以取得存款余额。 识别问题中的对象与属性 识别对象上的方法
使用class定义类别 在Java中使用"class"关键词来定义类别 public class Account { private String accountNumber; privatedouble balance; public Account(){ this("empty", 0.0); } public Account(String accountNumber, double balance) { this.accountNumber = accountNumber; this.balance = balance; } … 定义类别 定义建构方法
使用class定义类别 在Java中使用"class"关键词来定义类别 … publicString getAccountNumber() { return accountNumber; } publicdouble getBalance() { return balance; } publicvoid deposit(double money) { balance += money; } publicdouble withdraw(double money) { balance -= money; return money; } } 定义成员
使用class定义类别 Account account = new Account(); System.out.println("帐戶: " + account.getAccountNumber()); System.out.println("余額: " + account.getBalance()); account = new Account("123-4567", 100.0); account.deposit(1000.0); System.out.println("帐戶: " + account.getAccountNumber()); System.out.println("余額: " + account.getBalance());
使用class定义类别 可根据类别来建构对象 要透过公开成员来操作对象或取得对象信息的话,可以在对象名称后加上「.」运算符来进行 Account account1= newAccount(); Account account2 =newAccount("123-4567", 100.0); account1.getBalance(); account1.deposit(1000.0);
类别成员(Classmember) 类别成员可用的访问权限修饰词有“public”、“protected”、“private”三个 在宣告成员时不使用存取修饰词,则预设以「套件」(package)为存取范围
类别成员(Classmember) 数据成员被宣告为“private”,表示它是 「私用成员」(Privatemember),私用成员只能在类别中被使用 方法被宣告为"public",表示这些方法可以藉由对象的参考名称加上"."直接呼叫 存取修饰 传回值型态 方法名称(参数列) { //实作 return传回值; }
类别成员(Classmember) 方法区块中可以宣告变量(Variable),参数在方法区块执行结束后就会自动清除 方法中的相同变量名称会暂时覆盖数据成员的作用范围 可以使用"this"关键词来特别指定
类别成员(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; } }
类别成员(Class member) 信息的最小化 如果数据成员能不公开就不公开 透过公开方法存取私用成员的好处 如果存取私用成员的流程有所更动,只要在公开方法中修改就可以了 public double withdraw(double money) { if(balance – money < 0) { return 0; } else { balance -= money; return money; } }
建构方法(Constructor) 建构方法是与类别名称相同的公开方法成员,且没有传回值 public class SafeArray { // .. public SafeArray() { //建构方法 // .... } public SafeArray(参数列) {//建构方法 // .... } }
建构方法(Constructor) public class SafeArray { private int[] arr; public SafeArray() { this(10); //预设10个元素 } public SafeArray(int length) { arr = new int[length]; } … }
关于this 方法成员在内存中会只有一份
关于this 使用参考名称来呼叫对象的方法成员时,程序会将对象的参考告知方法成员 在方法中所撰写的每一个数据成员其实会隐含一个this参考名称 this名称参考至呼叫方法的对象 public double getBalance() { return this.balance; }
关于this 在方法中使用数据成员时,都会隐含的使用this名称 public Account(String accountNumber, double balance) { this.accountNumber = accountNumber; this.balance = balance; } public Account(String number, double money) { accountNumber = number; //实际等于this.accountNumber = number; this.balance = money; //实际等于this.balance = money; }
关于this this还有一种可以带自变量的用法,主要是用于呼叫建构方法 public class Ball { private String name; public Ball() { this(“No name”); //会使用Ball(“No name”)来建构 } public Ball(String name) { this.name = name; .... } }
关於static 被宣告为“static”的数据成员,又称「静态数据成员」 静态成员是属于类别所拥有,而不是个别的对象 可以将静态成员视为每个对象实例所共享的数据成员 public class Ball { public static double PI = 3.14159; //宣告static资料 ... }
关于static 属于类别所拥有,可以在不使用名称参考下,直接使用类别名称加上‘.’运算符来存取 同样遵守“public”、“protected”与“private”的存取限制 设定为“public”成员的话就可以如下存取 下面的方式是不被鼓励的 System.out.println("PI = " + Ball.PI); Ball ball = new Ball(); System.out.println("PI = " + ball.PI);
关于static 可以宣告方法成员为"static"方法,又称「静态方法」 public class Ball { ... public static double toRadian(double angle) { return 3.14159 / 180 * angle; } } System.out.println("角度90等于径度" + Ball.toRadian (90));
关于static 静态方法中不会有this参考名称 静态方法中不允许使用非静态成员 在静态方法中不能呼叫非静态方法 non-static variable test cannot be referenced from a static context non-static method showHello() cannot be referenced from a static context
关于static 可以使用“static”定义一个静态区块,并在当中撰写类别载入时的初始化动作 在类别被加载时,默认会先执行静态区块中的程序代码,且只会执行一次 public class Ball { static { //一些初始化程序代码 } .... }
重载(Overload)方法 为类似功能的方法提供统一名称,可根据参数列的不同而自动呼叫对应的方法 String的valueOf()方法就提供了多个版本 static String valueOf(boolean b) static String valueOf(char c) static String valueOf(char[] data) static String valueOf(char[] data, int offset, int count) static String valueOf(double d) static String valueOf(float f) static String valueOf(int i) static String valueOf(long l) static String valueOf(Object obj)
重载(Overload)方法 参数个数也可以用来设计方法重载 public class SomeClass { //以下重载了someMethod()方法 public void someMethod() { // ... } public void someMethod(int i) { // ... } public void someMethod(float f) { // ... } public void someMethod(int i, float f) { // ... } }
重载(Overload)方法 返回值型态不可用作为方法重载的区别根据,以下是不正确的 public class SomeClass { public int someMethod(int i) { // ... return 0; } public double someMethod(int i) { // ... return 0.0; } }
重载(Overload)方法 注意到autoboxing、unboxing的问题 public static void main(String[] args) { someMethod(1); } public static void someMethod(int i) { System.out.println("int版本被呼叫"); } public static void someMethod(Integer integer) { System.out.println("Integer版本被呼叫"); }
重载(Overload)方法 注意到autoboxing、unboxing的问题 找寻在还没有装箱动作前可以符合自变量个数与型态的方法 尝试装箱动作后可符合自变量个数与型态的方法 尝试设有「不定长度自变量」并可以符合的方法 编译程序找不到合适的方法,回报编译错误
不定长度自变量 J2SE5.0之后开始支持「不定长度自变量」(Variable-lengthArgument) 实际上nums是一个数组 public static int sum(int... nums) { //使用...宣告参数 int sum = 0; for(int num : nums) { sum += num; } return sum; }
不定长度自变量 宣告的参数必须设定在参数列的最后一个,下面的方式是合法的 下面的方式是不合法的 public void someMethod(int arg1, int arg2, int... varargs) { // .... } public void someMethod(int... varargs, int arg1, int arg2) { // .... }
不定长度自变量 没办法使用两个以上的不定长度自变量,下面的方式是不合法的 如果使用对象的不定长度自变量,宣告的方法相同 public void someMethod(int... varargs1, int... varargs2) { // .... } public void someMethod(SomeClass... somes) { // .... }
递归方法 在方法中呼叫自身同名方法,而呼叫者本身会先被置入内存「堆栈」(Stack)中 堆栈是一种「先进后出」(First in, lastout)的数据结构 private static int gcd(int m, int n) { if(n == 0) return m; else return gcd(n, m % n); }
垃圾收集( Garbage Collector ) • Java提供垃圾收集机制,不再使用的内存空间应回收-垃圾收集。 • 在C/C++ 等语言中,由程序员负责回收无用内存。 • Java语言消除了程序员回收无用内存空间的责任;它提供一种系统级线程跟踪存储空间的分配情况。并在JVM的空闲时,检查并释放那些可被释放的存储器空间。
垃圾收集 垃圾收集在Java程序运行过程中自动进行,程序员无法精确控制和干预在程序执行的空闲时候,程序员可以建议执行环境进行垃圾收集,但也仅止于建议 在适当的时候,Java执行环境会自动检查对象,看看是否有未被参考的对象 如果有的话就清除对象、回收对象所占据的内存空间
垃圾收集 finalize()会在对象被回收时执行 因为不知道对象资源何时被回收,所以也就不知道finalize()真正被执行的时间
垃圾收集 public class GcTest { private String name; public GcTest(String name) { this.name = name; System.out.println(name + "建立"); } //对象回收前执行 protected void finalize() { System.out.println(name + "被回收"); } }.