970 likes | 1.18k Views
Java 程序设计系列讲座- 2 面向对象程序设计. 黄绍辉 厦门大学计算机科学系 E-mail: hsh@xmu.edu.cn. 面向对象程序设计( OOP )基本思想. 对象的基本概念 对象是系统中用来描述客观事物的一个实体,它是构成系统的一个基本单位。一个对象由 一组属性 和对这组属性进行操作的 一组服务 组成。 对象是问题域或实现域中某些事物的一个抽象,它反映该事物在系统中需要保存的信息和发挥的作用;它是一组属性和有权对这些属性进行操作的一组服务的封装体。 客观世界是由对象和 对象之间的联系组成。. 类的基本概念.
E N D
Java程序设计系列讲座-2面向对象程序设计 黄绍辉 厦门大学计算机科学系 E-mail: hsh@xmu.edu.cn
面向对象程序设计(OOP)基本思想 • 对象的基本概念 • 对象是系统中用来描述客观事物的一个实体,它是构成系统的一个基本单位。一个对象由一组属性和对这组属性进行操作的一组服务组成。 • 对象是问题域或实现域中某些事物的一个抽象,它反映该事物在系统中需要保存的信息和发挥的作用;它是一组属性和有权对这些属性进行操作的一组服务的封装体。 • 客观世界是由对象和对象之间的联系组成。
类的基本概念 • 类是具有相同属性和服务的一组对象的集合。分类的原则是抽象。 • 在面向对象的编程语言中,类是一个独立的程序单位,它应该有一个类名并包括属性说明和服务说明两个主要部分。 • 例如图上的三种车,可以做成一个类。具体到某一辆车子,就是一个具体对象。
面向对象的基本特征 • 封装性 • 把对象的属性和服务结合成一个独立的相同单位,并尽可能隐蔽对象的内部细节。 • 继承性 • 从一个已有的类来构造新类,除了保留原有的类的特性,还增加了一些新特性。已有的类称为父类superclass,新类称为子类subclass。 • 多态性 • 在父类中定义的属性或服务被特殊类继承之后,可以具有不同的数据类型或表现出不同的行为。
面向对象程序设计的框架 • 用对象的思想来组织程序模块。每一个程序至少有一个对象(class); • 对象与对象之间一般是并列关系,也可以有包含关系; • 对象可以拥有两种东西:属性和服务。属性是一堆的变量,服务是一堆的函数。它们都是对象的成员,所以又叫成员变量、成员函数; • 面向对象的程序设计分两步:一是先独立创建各种对象,好好设计每个对象的属性和服务;二是在main函数中使用各个对象,让对象按照设计的流程发挥各自的作用。
先来学习怎么使用类 数组专题
数组 • Java的数组是用纯正OOP的方法设计的,所有专门有一个类,叫Array,用来实现数组的功能。 • 尽管我们刚刚知道,类和对象还是不同的,但是今后我们不太区分这两个词汇;如果要细究,可以自己结合上下文理解。 • 下面我们来学习如果使用人家做好的类,等有感觉了再来做自己的类。
数组入门-1 • 1 声明一个数组 • 数据类型[] 数组名; • or • 数据类型 数组名[]; • 例如:double[] myList;int a[]; • 2 创建一个数组 • 数组名 = new 数据类型[数组长度]; • 如:myList = new double[10];
数组入门-2 • 合并前两步,声明并创建一个数组 • 数据类型[] 数组名 = new 数据类型[数组长度]; • or • 数据类型 数组名[] = new 数据类型[数组长度]; • 例如:double[] myList = new double[10];int a[] = new int[10]; • 友情提醒:要使用一个对象,都需要先声明,再创建,然后才能使用,两步缺一不可;当然这两步可以合并,例如上面的例子。 • 声明的作用仅仅是弄出一个空对象(null)。
数组入门-3 • 数组在创建(new)之后,Java才会为这个数组自动分配空间。(注意声明数组的时候并没有分配数组元素的空间,因为那时候不知道数组多大,所以只是一个空数组,无法容纳任何元素)
数组入门-4 • 任何一个数组,都可以通过属性length得到数组的长度。如: myList.length • 数组创建的时候会自动赋零值,对于数值型的,就是0或者0.0或者'\0',对于布尔型的,就是false • 任何一个数组,其元素的最小下标是0,最大下标是length-1 • 数组下标越界会引发异常
数组入门-5 • 数组元素的引用使用[ ],以下两个方法等价,都可以打印出数组myList的每一个元素值: for (int i = 0; i < myList.length; i++) { System.out.print(" "+myList[i]); } 或者(JDK1.5及以上版本才支持的) for (int val : myList) { System.out.print(" "+val); }
数组入门-6 • 数组在创建的时候可以顺便初始化,如: • double[] myList = {1.9, 2.9, 3.4, 3.5}; • 它相当于: • double[] myList = new double[4]; • myList[0] = 1.9; • myList[1] = 2.9; • myList[2] = 3.4; • myList[3] = 3.5;
数组例程-1/3 • 用100以内随机数初始化数组 for (int i = 0; i < myList.length; i++) { myList[i] = Math.random() * 100; }
数组例程-2/3 • 数组求和 double total = 0; for (int i = 0; i < myList.length; i++) { total += myList[i]; }
数组例程-3/3 • 求数组中的最大值 double max = myList[0]; for (int i = 1; i < myList.length; i++) { if (myList[i] > max) max = myList[i]; }
复制数组-1 • 假设list1和list2都是数组,执行语句:list2 = list1 • 上述语句并不能将list1全部复制给list2,而是仅仅让list2变成list1的引用。换言之,此时list2和list1表示同一个数组,原先list2数组的元素就全被抛弃在内存的某一处,找不回来了!
复制数组-2 • 为了复制一个数组到另一个数组,可以自己写一个循环,一个一个复制。例如,有两个数组: int[] sourceArray = {2, 3, 1, 5, 10}; int[] targetArray = new int[sourceArray.length]; • 一个一个搬的例子 for (int i = 0; i < sourceArray.length; i++) { targetArray[i] = sourceArray[i]; }
总结一下 • 假设Student是一个类,要使用这个类,必须这样: • Student a, b; //先声明 • a = new Student(); b = new Student(); //再创建 • //下面可以随意折腾a和b了,它们是两个对象 • 对象之间不能通过=完成复制,例如在上面代码的基础上,使用a=b,不是把b的内容给a,而是让a和b共享b的对象;原先a的内容就被a抛弃了。
数组作为函数参数-1 • 对象(包括数组)作为参数,Java采用的是引用传递方式,基本数据类型(int,char等)作为参数,采用值传递方式。 • 简单一点说,引用传递方式,实际参数和形式参数,操作的其实是同一个对象;值传递方式,实际参数和形式参数,仅仅是值相等而已。 • Java中,所有被用作参数的对象,都采用引用方式传递以提高效率(类似于C中的地址传递,因为Java的对象实在太大只了,所有成员都复制一遍不划算,复制对象起始地址就好)
数组作为函数参数-2 public class Test { public static void main(String[] args) { int x = 1; // x represents an int value int[] y = new int[10]; // y represents an array of int values m(x, y); // Invoke m with arguments x and y System.out.println("x is " + x);// x值不变,还是1 System.out.println("y[0] is " + y[0]);// y[0]值已改变,本来是0的 } public static void m(int number, int[] numbers) { number = 1001; // Assign a new value to number numbers[0] = 5555; // Assign a new value to numbers[0] } }
数组作为函数参数-3 1 public class TestPassArray { 2 /** Main method */ 3 public static void main(String[] args) { 4 int[] a = {1, 2}; 5 6 // Swap elements using the swap method 7 System.out.println("Before invoking swap"); 8 System.out.println("array is {" + a[0] + ", " + a[1] + "}"); 9 swap(a[0], a[1]);//值传递,返回后不改变原值 10 System.out.println("After invoking swap"); 11 System.out.println("array is {" + a[0] + ", " + a[1] + "}"); 12 13 // Swap elements using the swapFirstTwoInArray method 14 System.out.println("Before invoking swapFirstTwoInArray"); 15 System.out.println("array is {" + a[0] + ", " + a[1] + "}"); 16 swapFirstTwoInArray(a);//引用传递,返回后原值可能改变 17 System.out.println("After invoking swapFirstTwoInArray"); 18 System.out.println("array is {" + a[0] + ", " + a[1] + "}"); 19 }
数组作为函数参数-4 20//值传递,返回后不改变原值 21 /** Swap two variables */ 22 public static void swap(int n1, int n2) { 23 int temp = n1; 24 n1 = n2; 25 n2 = temp; 26 } 27//引用传递,返回后原值可能改变 28 /** Swap the first two elements in the array */ 29 public static void swapFirstTwoInArray(int[] array) { 30 int temp = array[0]; 31 array[0] = array[1]; 32 array[1] = temp; 33 } 34 }
再来一个例子 class ClassA { int a = 1; } publicclass Main { staticvoid f1(int a) { a++; } staticvoid f2(ClassA c) { c.a++; } publicstaticvoid main(String[] args) { ClassA c = new ClassA(); System.out.println(“a=”+c.a); //输出a=1 f1(c.a); //基本数据类型做参数,c.a不变 System.out.println("a="+c.a); //输出a=1 f2(c); //引用数据类型做参数,c改变 System.out.println("a="+c.a); //输出a=2 } }
数组作为函数返回值 • 函数的返回值是通过return带回来的,每次return可以带回一个基本类型的值(char、int等),也可以带回一个对象(例如数组)
一个例子:计算字符出现的次数 • 解题思路: • 随机生成100个小写字母,放在数组chars中;显然,这个数组的大小应该是100; • 利用counts数组存储字符出现的次数,下标0,1,2,...分别存储'a','b','c',...的次数;显然,这个数组的大小应该是26。 • 生成随机小写字母可以借助于Math.random()
关键代码-1/5 20 /** Create an array of characters */ 21 public static char[] createArray() { 22 // Declare an array of characters and create it 23 char[] chars = new char[100]; 24 25 // Create lowercase letters randomly and assign 26 // them to the array 27 for (int i = 0; i < chars.length; i++) 28 chars[i] = RandomCharacter.getRandomLowerCaseLetter(); 29 30 // Return the array 31 return chars; 32 }
关键代码-2/5 34 /** Display the array of characters */ 35 public static void displayArray(char[] chars) { 36 37 for (int i = 0; i < chars.length; i++) { 38 if ((i + 1) % 20 == 0) 39 System.out.println(chars[i] + " "); 40 else 41 System.out.print(chars[i] + " "); 42 } 43 }
关键代码-3/5 45 /** Count the occurrences of each letter */ 46 public static int[] countLetters(char[] chars) { 47 // Declare and create an array of 26 int 48 int[] counts = new int[26]; 49 50 // For each lowercase letter in the array, count it 51 for (int i = 0; i < chars.length; i++) 52 counts[chars[i] - 'a']++; 53 54 return counts; 55 }
关键代码-4/5 57 /** Display counts */ 58 public static void displayCounts(int[] counts) { 59 for (int i = 0; i < counts.length; i++) { 60 if ((i + 1) % 10 == 0) 61 System.out.println(counts[i] + " " + (char)(i + 'a')); 62 else 63 System.out.print(counts[i] + " " + (char)(i + 'a') + " "); 64 } 65 }
关键代码-5/5 3 public static void main(String args[]) { 4 // Declare and create an array 5 char[] chars = createArray(); 6 7 // Display the array 8 System.out.println("The lowercase letters are:"); 9 displayArray(chars); 10 11 // Count the occurrences of each letter 12 int[] counts = countLetters(chars); 13 14 // Display counts 15 System.out.println(); 16 System.out.println("The occurrences of each letter are:"); 17 displayCounts(counts); 18 }
多维数组-1 • 二维数组的定义 • 数据类型[][] 数组名; • or • 数据类型 数组名[][]; • 例如: • int[][] matrix; • 或 int matrix[][]; • 注意,这里仅仅说明matrix是一个二维数组,但是这个数组目前是null,所以还不能存储元素。
多维数组-2 • 二维数组有行和列的概念,如:
多维数组-3 • 二维数组可以在声明的时候赋初值,也可以在new之后再一个一个慢慢赋值。 • 其实二维数组行和行之间是相互独立的,每一行都相当于一个一维数组。
多维数组-4 • 由于二维数组的每一行是一个一维数组,所以这些一维数组的大小不必相等,如: • 此时: triangleArray.length = 5, //因为数组有5行 triangleArray[0].length = 5, triangleArray[1].length = 4, triangleArray[2].length = 3, triangleArray[3].length = 2, triangleArray[4].length = 1.
二维数组例程-1 • 随机数填充 for (int row = 0; row < matrix.length; row++) { for (int column = 0; column < matrix[row].length; column++) { matrix[row][column] = (int)(Math.random() * 100); } } • 这里matrix是二维数组。过一遍二维数组必须用两层的循环,一般用i循环行,j循环列;如果英文好一点,可以用row循环行,column或者col循环列。
二维数组例程-2 • 打印数组元素 for (int row = 0; row < matrix.length; row++) { for (int column = 0; column < matrix[row].length; column++) { System.out.print(matrix[row][column] + " "); } System.out.println(); }
二维数组例程-3 • 数组求和 int total = 0; for (int row = 0; row < matrix.length; row++) { for (int column = 0; column < matrix[row].length; column++) { total += matrix[row][column]; } }
一个例子:试卷评分 • 假设让计算机改卷,8张试卷和标准答案如下:
关键代码 • 学生的试卷存储在answers二维数组中,答案在keys一维数组中,则评分的代码是: 18 // Grade all answers 19 for (int i = 0; i < answers.length ; i++) { 20 // Grade one student 21 int correctCount = 0; 22 for (int j = 0; j < answers[i].length ; j++) { 23 if (answers[i][j] == keys[j]) 24 correctCount++; 25 } 26 27 System.out.println("Student " + i + "'s correct count is " + 28 correctCount); 29 }
再来学习怎么使用类 字符串专题
字符串类-1 • 字符串是Java另一个常用类。 • 创建一个字符串(三种方法均可) • String message = new String("Welcome to Java"); • String message = "Welcome to Java"; • char[] charArray = {'G', 'o', 'o', 'd'}; String message = new String(charArray);
字符串类-2 • 字符串的内容是常量,一旦创建就无法修改。 • String s = "Java"; • s = “HTML”;//友情提醒:这句是对的。但是这不是串复制,只是一个s抛弃了“Java”字符串的故事。 • 以上第2行代码仅仅修改了s的指向,但是没有改动到"Java"这个字符串本身,如图:
字符串类-3 • 正宗的字符串内容判等函数,是equals,不是==(这个符号相当于比较对象地址是否相等) • String s1 = new String("Welcome to Java"); • String s2 = "Welcome to Java"; • System.out.println("s1 == s2 is " + (s1 == s2)); • System.out.println("s1.equals(s2) is " + (s1.equals(s2))); • 字符串内容比较函数,用compareTo • s1.compareTo(s2),其返回值相当于s1-s2,相等为0
字符串类-4 • 字符串长度函数length() • String message = new String("Welcome to Java"); • int len = message.length(); • 注意:数组也有长度的概念,但是数组的长度被设计为数组的属性而不是函数。 • int[] arr = new int[5]; • int len = arr.length; • 取字符串的单个字符charAt() • message.charAt(index) 下标范围是0..s.length()–1
字符串类-5 • 字符串拼接concat()或者+ • String s3 = s1.concat(s2); • 等价于:String s3 = s1 + s2; • 截取子串substring • String message = "Welcome to Java".substring(0, 11) + "HTML"; //相当于从0开始,到11为止的子串(不包括11) • 如果没有提供endIndex,相当于截取到串尾
字符串类-6 • 字符串转换 • "Welcome". toLowerCase() //返回welcome • "Welcome". toUpperCase() //返回WELCOME • " Welcome". trim() //返回Welcome • "Welcome". replace('e', 'A') //返回WAlcomA • "Welcome". replaceFirst("e", "A") //返回WAlcome • "Welcome". replaceAll("e", "A") //返回WAlcomA
字符串类-7 • 查找指定的字符或者子串 • indexOf(char ch) //查找指定字符,返回下标 • lastIndexOf(char ch) //同上,但是逆向查找 • indexOf(int ch, int fromIndex) 从下标fromIndex开始查找指定字符 • lastIndexOf(int ch, int endIndex) 同上,但是从下标endIndex开始逆向查找 • 以上函数都有字符串版本,把参数换成String就可以了。如果查找失败,返回值都是-1。因为这是个无效的下标。
字符串类-8 • "Welcome to Java".indexOf('W') returns 0. • "Welcome to Java".indexOf('o') returns 4. • "Welcome to Java".indexOf('o', 5) returns 9. • "Welcome to Java".indexOf("come") returns 3. • "Welcome to Java".indexOf("Java", 5) returns 11. • "Welcome to Java".indexOf("java", 5) returns -1. • "Welcome to Java".lastIndexOf('W') returns 0. • "Welcome to Java".lastIndexOf('o') returns 9. • "Welcome to Java".lastIndexOf('o', 5) returns 4. • "Welcome to Java".lastIndexOf("come") returns 3. • "Welcome to Java".lastIndexOf("Java", 5) returns -1. • "Welcome to Java".lastIndexOf("java", 5) returns -1.
字符串类-9 • 字符串分拆到字符数组toCharArray • char[] chars = "Java".toCharArray(); • 用字符串的子串去填充数组getChars • char[] dst = {'J', 'A', 'V', 'A', '1', '3', '0', '1'}; • "CS3720".getChars(2, 6, dst, 4); • 头两个参数取子串,后面是填充目标数组和起始位置 • 字符数组拼成字符串String或valueOf • String str = new String(new char[]{'J', 'a', 'v', 'a'}); • String str = String.valueOf(new char[]{'J', 'a', 'v', 'a'});