目录
范例1-10:为Book类中的封装属性设置setter、getter操作。
范例1-38:回避NullPointerException问题。
范例1-44:取出指定索引的字符——使用charAt()方法。
范例1-52:利用indexOf()方法判断子字符串是否存在。
范例1-53:使用contains()方法判断子字符串是否存在。
范例1-82:代码实现(无参构造、setter、getter略,同时本程序定义的是两个简单Java类)。
范例1-92:在没有实例化对象产生时直接操作static属性。
范例1-115:手工配置节点关系,并使用while循环输出全部节点数据。
范例1-116:手工配置节点关系,通过递归输出全部节点数据。
范例1-124:在Link类里面增加一个foot的属性,表示每一个Node元素的编号。
范例1-125:在每一次查询时(一个链表可能查询多次),foot应该都从头开始计算(foot设为0)。
范例1-126:在Node类里面实现getNode()方法,内部类和外部类之间可以方便地进行私有属性的互相访问。
范例1-127:在Node类里面增加setNode()方法。
范例1-128:在Node类里面增加一个removeNode()方法,此方法专门负责处理非根节点的删除。
范例1-134:修改链表实现(本代码主要是将之前的链表类中的String类型更换为Book类型,对象比较更换为compare()方法)。
第一章:面向对象基础知识
1.2 类与对象
范例1-1:定义类。
class Book { // 定义一个新的类 String title; // 书的名字 double price; // 书的价格 /** * 输出对象完整信息 */ public void getInfo() { // 此方法将由对象调用 System.out.println("图书名称:" + title + ",价格:" + price); } } |
范例1-2:使用类——在主类中使用Book类。
class Book { // 定义一个新的类 String title; // 书的名字 double price; // 书的价格 public void getInfo() { // 此方法将由对象调用 System.out.println("图书名称:" + title + ",价格:" + price); } } public class TestDemo { public static void main(String args[]) { Book bk = new Book() ; // 声明并实例化对象 bk.title = "Java开发" ; // 操作属性内容 bk.price = 89.9 ; // 操作属性内容 bk.getInfo() ; // 调用类中的getInfo()方法 } } |
范例1-3:以分步的方式实例化对象。
public class TestDemo { public static void main(String args[]) { Book bk = null; // 声明对象 bk = new Book(); // 实例化对象(开辟了堆内存) bk.title = "Java开发"; // 操作属性内容 bk.price = 89.9; // 操作属性内容 bk.getInfo(); // 调用类中的getInfo()方法 } } |
范例1-4:使用未实例化的对象。
public class TestDemo { public static void main(String args[]) { Book bk = null; // 声明对象 bk.title = "Java开发"; // 操作属性内容 bk.price = 89.9; // 操作属性内容 bk.getInfo(); // 调用类中的getInfo()方法 } } |
范例1-5:声明两个对象。
public class TestDemo { public static void main(String args[]) { Book bookA = new Book() ; // 声明并实例化第一个对象 Book bookB = new Book() ; // 声明并实例化第二个对象 bookA.title = "Java开发" ; // 设置第一个对象的属性内容 bookA.price = 89.8 ; // 设置第一个对象的属性内容 bookB.title = "JSP开发" ; // 设置第二个对象的属性内容 bookB.price = 69.8 ; // 设置第二个对象的属性内容 bookA.getInfo() ; // 调用类中的方法输出信息 bookB.getInfo() ; // 调用类中的方法输出信息 } } |
范例1-6:对象引用传递。
public class TestDemo { public static void main(String args[]) { Book bookA = new Book() ; // 声明并实例化第一个对象 Book bookB = null ; // 声明第二个对象 bookA.title = "Java开发" ; // 设置第一个对象的属性内容 bookA.price = 89.8 ; // 设置第一个对象的属性内容 bookB = bookA ; // 引用传递 bookB.price = 69.8 ; // 利用第二个对象设置属性内容 bookA.getInfo() ; // 调用类中的方法输出信息 } } |
范例1-7:深入观察引用传递。
public class TestDemo { public static void main(String args[]) { Book bookA = new Book() ; // 声明并实例化第一个对象 Book bookB = new Book() ; // 声明并实例化第二个对象 bookA.title = "Java开发" ; // 设置第一个对象的属性内容 bookA.price = 89.8 ; // 设置第一个对象的属性内容 bookB.title = "JSP开发" ; // 设置第二个对象的属性内容 bookB.price = 69.8 ; // 设置第二个对象的属性内容 bookB = bookA ; // 引用传递 bookB.price = 100.1 ; // 利用第二个对象设置属性内容 bookA.getInfo() ; // 调用类中的方法输出信息 } } |
1.3 封装性初步分析
范例1-8:观察没有封装的代码。
class Book { // 定义一个新的类 String title; // 书的名字 double price; // 书的价格 public void getInfo() { // 此方法将由对象调用 System.out.println("图书名称:" + title + ",价格:" + price); } } public class TestDemo { public static void main(String args[]) { Book book = new Book(); // 声明并实例化对象 book.title = "Java开发"; // 设置属性内容 book.price = -89.9; // 设置属性内容 book.getInfo(); // 调用方法 } } |
范例1-9:使用private封装属性。
class Book { // 定义一个新的类 private String title; // 书的名字 private double price; // 书的价格 public void getInfo() { // 此方法将由对象调用 System.out.println("图书名称:" + title + ",价格:" + price); } } public class TestDemo { public static void main(String args[]) { Book book = new Book(); // 声明并实例化对象 book.title = "Java开发"; // 设置属性内容 book.price = -89.9; // 设置属性内容 book.getInfo(); // 调用方法 } } |
范例1-10:为Book类中的封装属性设置setter、getter操作。
class Book { // 定义一个新的类 private String title; // 书的名字 private double price; // 书的价格 /** * 设置或修改title属性内容 * @param t 接收要设置的数据 */ public void setTitle(String t) { // 设置title属性内容 title = t; } /** * 设置或修改price属性内容 * @param p 接收要设置的数据 */ public void setPrice(double p) { // 设置price属性内容 if (p > 0.0) { // 进行数据验证 price = p ; } } /** * 取得title属性内容 * @return title属性数据 */ public String getTitle() { // 取得title属性内容 return title; } /** * 取得price属性内容 * @return price属性数据 */ public double getPrice() { // 取得price属性内容 return price; } /** * 输出对象完整信息 */ public void getInfo() { // 此方法将由对象调用 System.out.println("图书名称:" + title + ",价格:" + price); } } public class TestDemo { public static void main(String args[]) { Book book = new Book(); // 声明并实例化对象 book.setTitle("Java开发"); // 设置属性内容 book.setPrice(-89.9); // 设置属性内容 book.getInfo(); // 调用方法 } } |
1.4 构造方法
范例1-11:定义构造方法。
class Book { // 定义一个新的类 /** * Book类无参构造方法 */ public Book() { // 构造方法 System.out.println("************************"); } } public class TestDemo { public static void main(String args[]) { Book book = null ; // 声明对象不调用构造 book = new Book() ; // 实例化对象调用构造 } } |
范例1-12:利用构造方法为属性赋值。
class Book { // 定义一个新的类 private String title; // 书的名字 private double price; // 书的价格 /** * Book类构造方法,用于设置title与price属性的内容 * @param t title属性内容 * @param p price属性内容 */ public Book(String t,double p) { // 定义构造方法 setTitle(t) ; // 调用本类方法 setPrice(p) ; // 调用本类方法 } public void setTitle(String t) { // 设置title属性内容 title = t; } public void setPrice(double p) { // 设置price属性内容 price = p ; } public String getTitle() { // 取得title属性内容 return title; } public double getPrice() { // 取得price属性内容 return price; } public void getInfo() { // 此方法将由对象调用 System.out.println("图书名称:" + title + ",价格:" + price); } } public class TestDemo { public static void main(String args[]) { Book book = new Book("Java开发", 69.8); // 声明并实例化对象 book.getInfo(); // 调用方法 } } |
范例1-13:构造方法重载。
class Book { // 定义一个新的类 private String title; // 书的名字 private double price; // 书的价格 /** * Book类无参构造方法 */ public Book() { // 无参的,无返回值的构造方法 System.out.println("无参构造") ; } /** * Book类构造方法,用于设置title属性的内容 * @param t title属性内容 */ public Book(String t) { // 有一个参数的构造 title = t ; // 直接为属性赋值 System.out.println("有一个参数的构造") ; } /** * Book类构造方法,用于设置title与price属性的内容 * @param t title属性内容 * @param p price属性内容 */ public Book(String t,double p) { // 有两个参数的构造 title = t ; // 直接为属性赋值 price = p ; // 直接为属性赋值 System.out.println("有两个参数的构造") ; } // setter、getter略 public void getInfo() { // 此方法将由对象调用 System.out.println("图书名称:" + title + ",价格:" + price); } } public class TestDemo { public static void main(String args[]) { Book book = new Book("Java开发"); // 声明并实例化对象 book.getInfo(); // 调用方法 } } |
1.5 匿名对象
范例1-14:定义匿名对象。
class Book { // 定义一个新的类 private String title; // 书的名字 private double price; // 书的价格 public Book(String t,double p) { // 有两个参数的构造 title = t ; // 直接为属性赋值 price = p ; // 直接为属性赋值 } // setter、getter略 public void getInfo() { // 此方法将由对象调用 System.out.println("图书名称:" + title + ",价格:" + price); } } public class TestDemo { public static void main(String args[]) { new Book("Java开发", 69.8).getInfo(); // 匿名对象 } } |
1.6 简单Java类
范例1-15:开发Emp程序类。
class Emp { // 定义一个雇员类 private int empno; // 雇员编号 private String ename; // 雇员姓名 private String job; // 雇员职位 private double sal; // 基本工资 private double comm; // 佣金 public Emp() { // 明确定义一个无参构造方法 } public Emp(int eno, String ena, String j, double s, double c) { // 有参构造 empno = eno; // 为属性赋值 ename = ena; // 为属性赋值 job = j; // 为属性赋值 sal = s; // 为属性赋值 comm = c; // 为属性赋值 } public void setEmpno(int e) { // 设置empno属性内容 empno = e; } public void setEname(String e) { // 设置ename属性内容 ename = e; } public void setJob(String j) { // 设置job属性内容 job = j; } public void setSal(double s) { // 设置sal属性内容 sal = s; } public void setComm(double c) { // 设置comm属性内容 comm = c; } public int getEmpno() { // 取得empno属性内容 return empno; } public String getEname() { // 取得ename属性内容 return ename; } public String getJob() { // 取得job属性内容 return job; } public double getSal() { // 取得sal属性内容 return sal; } public double getComm() { // 取得comm属性内容 return comm; } /** * 取得简单Java类的基本信息,信息在被调用处输出 * @return 包含对象完整信息的字符串数据 */ public String getInfo() { // 取得完整信息 Return "雇员编号:" + empno + "\n" + "雇员姓名:" + ename + "\n" + "雇员职位:" + job + "\n" + "基本工资:" + sal + "\n" + "佣 金:" + comm ; } } |
范例1-16:编写测试程序。
public class TestDemo { public static void main(String args[]) { Emp e = new Emp(7369, "SMITH", "CLERK", 800.0, 1.0); // 实例化对象 System.out.println(e.getInfo()); // 取得对象信息 } } |
1.7 数组
范例1-17:定义数组。
public class ArrayDemo { public static void main(String args[]) { int data[] = new int[3]; // 声明并开辟了一个3个长度的数组 data[0] = 10; // 设置数组内容 data[1] = 20; // 设置数组内容 data[2] = 30; // 设置数组内容 for (int x = 0; x < data.length; x++) { // 循环输出数组 System.out.print(data[x] + "、"); } } } |
范例1-18:分步实现数组操作。
public class ArrayDemo { public static void main(String args[]) { int data [] = null ; // 声明数组 data = new int [3] ; // 开辟数组空间 data[0] = 10; // 设置数组内容 data[1] = 20; // 设置数组内容 data[2] = 30; // 设置数组内容 for (int x = 0; x < data.length; x++) { // 循环输出数组 System.out.print(data[x] + "、"); } } } |
范例1-19:数组的引用传递。
public class ArrayDemo { public static void main(String args[]) { int data[] = new int[3]; // 声明并开辟了一个3个长度的数组 data[0] = 10; // 设置数组内容 data[1] = 20; // 设置数组内容 data[2] = 30; // 设置数组内容 int temp[] = data; // 数组引用传递 temp[0] = 99; // 修改数组内容 for (int x = 0; x < data.length; x++) { // 循环输出数组 System.out.print(data[x] + "、"); } } } |
范例1-20:数组的静态初始化。
public class ArrayDemo { public static void main(String args[]) { int data[] = new int[] { 1, 2, 3, 4, 5 }; // 数组的静态初始化 for (int x = 0; x < data.length; x++) { // 循环输出数组 System.out.print(data[x] + "、"); } } } |
范例1-21:观察二维数组的定义及使用。
public class ArrayDemo { public static void main(String args[]) { int data [][] = new int [][] { {1,2,3} ,{4,5,6} , {7,8,9} } ; // 定义二维数组 for (int x = 0; x < data.length; x++) { // 外层循环是控制数组的数据行内容 for (int y = 0; y < data[x].length; y++) { // 内层循环是控制数组的数据列内容 System.out.print(data[x][y] + "\t"); } System.out.println(); // 换行 } } } |
范例1-22:一个数组传递的程序。
public class ArrayDemo { public static void main(String args[]) { int data[] = new int[] { 1, 2, 3 }; // 开辟数组 change(data); // 引用传递,等价于:int temp [] = data ; for (int x = 0; x < data.length; x++) { System.out.print(data[x] + "、"); } } /** * 此方法的主要功能是进行数组数据的改变操作,在本方法中会将数组中的每个元素内容乘2 * @param temp 要进行改变内容的数组引用 */ public static void change(int temp[]) { // 此方法定义在主类中,并且由主方法直接调用 for (int x = 0; x < temp.length; x++) { temp[x] *= 2; // 将数组的内容乘2保存 } } } |
范例1-23:简化理解。
public class ArrayDemo { public static void main(String args[]) { int data[] = new int[] { 1, 2, 3 }; // 开辟数组 int temp [] = data ; // 引用传递 for (int x = 0 ; x < temp.length ; x ++) { // 修改数组内容 temp[x] *= 2 ; // 将数组的内容乘2保存 } for (int x = 0; x < data.length; x++) { // 循环输出数据 System.out.print(data[x] + "、"); } } } |
范例1-24:实现一个数组排序。
数组的排序操作在笔试中经常被问到,下面给出(升序)排序的基本原理。
— 原始数据: 2、1、9、0、5、3、7、6、8;
— 第一次排序: 1、2、0、5、3、7、6、8、9;
— 第二次排序: 1、0、2、3、5、6、7、8、9;
— 第三次排序: 0、1、2、3、5、6、7、8、9。
以上只是给出了排序的基础原理过程,根据数据的不同会出现不同的排序次数,但是不管有多少个数据,总的排序次数不会超过数组的长度。所以只要排序的次数达到“长度*长度”,那么所有的数据一定可以排序成功。
(1)排序基础实现
public class ArrayDemo { public static void main(String args[]) { int data[] = new int[] { 2, 1, 9, 0, 5, 3, 7, 6, 8 }; System.out.print("排序前的数据:"); print(data); // 排序前输出数据 for (int x = 0; x < data.length; x++) { // 外层控制排序总体的次数 for (int y = 0; y < data.length - 1; y++) { // 内层控制每次的排序控制 if (data[y] > data[y + 1]) { // 判断是否需要交换 int t = data[y]; data[y] = data[y + 1]; data[y + 1] = t; } } } System.out.print("排序后的数据:"); print(data); // 排序后的输出数据 } /** * 此方法的主要功能是进行数组数据输出操作,在输出完成后会追加一个换行 * @param temp 要进行改变内容的数组引用 */ public static void print(int temp[]) { // 专门定义一个输出的功能的方法 for (int x = 0; x < temp.length; x++) { System.out.print(temp[x] + "、"); } System.out.println(); } } |
(2)改善设计
在代码编写中主方法是作为程序的起点存在的,所有的程序起点都可以称为客户端。既然是客户端,所有的代码编写一定要简单,因此可以采用方法进行封装。
public class ArrayDemo { public static void main(String args[]) { int data [] = new int [] {2,1,9,0,5,3,7,6,8} ; sort(data) ; // 实现排序 print(data) ; } /** * 数组排序操作,将接收到的数组对象内容进行升序排列 * @param arr 数组对象的引用 */ public static void sort(int arr[]) { // 这个方法专门负责排序 for (int x = 0 ; x < arr.length ; x ++) { // 外层控制排序总体的次数 for (int y = 0 ; y < arr.length - 1 ; y ++) { // 内层控制每次的排序控制 if (arr[y] > arr[y + 1]) { // 判断需要交换 int t = arr[y] ; arr[y] = arr[y + 1] ; arr[y + 1] = t ; } } } } public static void print(int temp[]) { // 专门定义一个输出的功能的方法 for (int x = 0 ; x < temp.length ; x ++) { System.out.print(temp[x] + "、") ; } System.out.println() ; } } |
范例1-25:实现数组的转置(首位交换)。
下面首先来解释一下转置的概念(一维数组实现)。
原始数组: 1、2、3、4、5、6、7、8;
转置后的数组: 8、7、6、5、4、3、2、1。
如果要想实现转置的操作,有以下两个思路。
— 解决思路一:首定义一个新的数组,然后将原始数组按照倒序的方式插入到新的数组中,最后改变原始数组引用,将其指向新的数组空间。
public class ArrayDemo { public static void main(String args[]) { int data [] = new int [] {1,2,3,4,5,6,7,8} ; int temp [] = new int [data.length] ; // 首先定义一个新的数组,长度与原始数组一致 int foot = data.length - 1; // 控制data数组的索引 for (int x = 0 ; x < temp.length ; x ++) { // 对于新的数组按照索引由小到大的顺序循环 temp[x] = data[foot] ; foot -- ; } // 此时temp的内容就是转置后的结果 data = temp ; // 让data指向temp,而data的原始数据就称为垃圾 print(data) ; // 输出数组 } public static void print(int temp[]) { // 专门定义一个输出功能的方法 for (int x = 0 ; x < temp.length ; x ++) { System.out.print(temp[x] + "、") ; } System.out.println() ; } } |
范例1-26:方法返回数组。
public class ArrayDemo { public static void main(String args[]) { int data[] = init() ; // 接收数组 print(data) ; System.out.println("数组长度:" + init().length) ; // 返回的数组可直接使用length取得长度 } /** * 数组初始化的操作方法,此方法可以返回一个数组的引用 * @return 包含3个元素的数组对象 */ public static int[] init() { // 方法返回数组 return new int [] {1,2,3} ; // 直接返回匿名数组 } public static void print(int temp[]) { // 数组输出 for (int x = 0 ; x < temp.length ; x ++) { System.out.print(temp[x] + "、") ; } System.out.println() ; } } |
范例1-27:实现数组复制。
— 数组A:1、2、3、4、5、6、7、8;
— 数组B:11、22、33、44、55、66、77、88;
— 将数组A的部分内容替换到数组B中,数组B的最终结果为:11、22、5、6、7、66、77、88。
public class ArrayDemo { public static void main(String args[]) { int dataA[] = new int[] { 1, 2, 3, 4, 5, 6, 7, 8 }; // 定义数组 int dataB[] = new int[] { 11, 22, 33, 44, 55, 66, 77, 88 };// 定义数组 System.arraycopy(dataA, 4, dataB, 2, 3); // 数组复制 print(dataB); } public static void print(int temp[]) { // 打印数组内容 for (int x = 0; x < temp.length; x++) { System.out.print(temp[x] + "、"); } System.out.println(); } } |
范例1-28:实现排序。
public class ArrayDemo { public static void main(String args[]) { int data[] = new int[] { 3, 6, 1, 2, 8, 0 }; java.util.Arrays.sort(data); // 数组排序 print(data); } public static void print(int temp[]) { // 数组输出 for (int x = 0; x < temp.length; x++) { System.out.print(temp[x] + "、"); } System.out.println(); } } |
范例1-29:对象数组的动态初始化。
class Book { private String title ; private double price ; public Book(String t,double p) { title = t ; price = p ; } // setter、getter、无参构造略 public String getInfo() { return "书名:" + title + ",价格:" + price ; } } public class ArrayDemo { public static void main(String args[]) { Book books [] = new Book[3] ; // 开辟了一个3个长度的对象数组,内容为null books[0] = new Book("Java",79.8) ; // 对象数组中的每个数据都需要分别实例化 books[1] = new Book("JSP",69.8) ; // 对象数组中的每个数据都需要分别实例化 books[2] = new Book("Android",89.8) ; // 对象数组中的每个数据都需要分别实例化 for (int x = 0 ; x < books.length ; x ++) { // 循环对象数组 System.out.println(books[x].getInfo()) ; } } } |
范例1-30:对象数组的静态初始化。
public class ArrayDemo { public static void main(String args[]) { Book books[] = new Book[] { new Book("Java", 79.8), new Book("JSP", 69.8), new Book("Android", 89.8) }; // 开辟了一个3个长度的对象数组 for (int x = 0; x < books.length; x++) { // 循环输出对象数组内容 System.out.println(books[x].getInfo()); } } } |
1.8 String类的基本概念
范例1-31:为String类对象直接赋值。
public class StringDemo { public static void main(String args[]) { String str = "www.YOOTK.com"; // 直接赋值 System.out.println(str); // 输出字符串数据 } } |
范例1-32:利用构造方法实例化。
public class StringDemo { public static void main(String args[]) { String str = new String("www.YOOTK.com"); // 直接赋值 System.out.println(str); // 输出字符串数据 } } |
范例1-33:判断两个int型整数是否相等。
public class StringDemo { public static void main(String args[]) { int x = 10; // 整型变量 int y = 10; // 整型变量 System.out.println(x == y); // 判断是否相等 } } |
范例1-34:在String对象上使用“==”比较。
public class StringDemo { public static void main(String args[]) { String stra = "hello"; // 直接赋值定义字符串 String strb = new String("hello"); // 构造方法定义字符串 String strc = strb; // 引用传递 System.out.println(stra == strb); // 比较结果:false System.out.println(stra == strc); // 比较结果:false System.out.println(strb == strc); // 比较结果:true } } |
范例1-35:实现字符串内容比较。
public class StringDemo { public static void main(String args[]) { String stra = "hello"; // 直接赋值定义字符串 String strb = new String("hello"); // 构造方法定义字符串 String strc = strb; // 引用传递 System.out.println(stra.equals(strb)) ; // 比较结果:true System.out.println(stra.equals(strc)) ; // 比较结果:true System.out.println(strb.equals(strc)) ; // 比较结果:true } } |
范例1-36:观察字符串是匿名对象的验证。
public class StringDemo { public static void main(String args[]) { String str = "hello"; // str是对象名称,而"hello"是内容 System.out.println("hello".equals(str)); // 内容比较,由字符串直接调用 } } |
范例1-37:观察问题。
public class StringDemo { public static void main(String args[]) { String input = null; // 假设这个内容由用户输入 if (input.equals("hello")) { // 如果输入内容是hello,认为满足一个条件 System.out.println("Hello World !!!"); } } } |
范例1-38:回避NullPointerException问题。
public class StringDemo { public static void main(String args[]) { String input = null; // 假设这个内容由用户输入 if ("hello".equals(input)) { // 如果输入内容是hello,认为满足一个条件 System.out.println("Hello World !!!"); } } } |
范例1-39:观察直接赋值时的堆内存自动引用。
public class StringDemo { public static void main(String args[]) { String stra = "hello"; // 直接赋值实例化 String strb = "hello"; // 直接赋值实例化 String strc = "hello"; // 直接赋值实例化 String strd = "yootk" ; // 直接赋值实例化,内容不相同 System.out.println(stra == strb); // 判断结果:true System.out.println(stra == strc); // 判断结果:true System.out.println(strb == strc); // 判断结果:true System.out.println(stra == strd); // 判断结果:false } } |
范例1-40:不自动保存对象池操作。
public class StringDemo { public static void main(String args[]) { String stra = new String("hello"); // 使用构造方法定义了新的内存空间,不会自动入池 String strb = "hello"; // 直接赋值 System.out.println(stra == strb); // 判断结果:false } } |
范例1-41:手工入池。
public class StringDemo { public static void main(String args[]) { String stra = new String("hello").intern(); // 使用构造方法定义新的内存空间,手工入池 String strb = "hello"; // 直接赋值 System.out.println(stra == strb); // 判断结果:true } } |
范例1-42:修改字符串对象引用。
public class StringDemo { public static void main(String args[]) { String str = "Hello "; // 直接赋值实例化String类对象 str = str + "World "; // 字符串连接,同时修改String类对象的引用关系 str += "!!!"; // 字符串连接,同时修改String类对象的引用关系 System.out.println(str); // 输出当前的String类对象内容 } } |
范例1-43:观察以下代码问题。
public class StringDemo { public static void main(String args[]) { String str = ""; // 实例化字符串对象 for (int x = 0; x < 1000; x++) { // 循环1000次 str += x; // 修改字符串对象引用 } System.out.println(str); } } |
1.9 String类的常用方法
范例1-44:取出指定索引的字符——使用charAt()方法。
public class StringDemo { public static void main(String args[]) { String str = "hello"; // 定义字符串对象 char c = str.charAt(0); // 截取第一个字符 System.out.println(c); // 输出字符 } } |
范例1-45:字符数组与字符串的转换。
public class StringDemo { public static void main(String args[]) { String str = "hello"; // 定义字符串 char[] data = str.toCharArray(); // 将字符串变为字符数组 for (int x = 0; x < data.length; x++) { // 循环输出每一个字符 System.out.print(data[x] + "、"); } } } |
范例1-46:将字符串转为大写。
public class StringDemo { public static void main(String args[]) { String str = "hello"; // 字符串由小写字母组成 char[] data = str.toCharArray(); // 将字符串变为字符数组 for (int x = 0; x < data.length; x++) { // 改变每一个字符的编码值 data[x] -= 32; } System.out.println(new String(data)); // 将全部字符数组变为String System.out.println(new String(data, 1, 2)); // 将部分字符数组变为String } } |
范例1-47:给定一个字符串,要求判断其是否由数字组成。
思路:如果整个字符串要判断是不是数字是无法实现的,但是可以将字符串变为字符数组,然后判断每一个字符的内容是否是数字,如果该字符的范围在('0'~'9')指定的范畴之内,那么就是数字。
public class StringDemo { public static void main(String args[]) { String str = "123423432"; if (isNumber(str)) { System.out.println("字符串由数字组成!"); } else { System.out.println("字符串由非数字组成!"); } } /** * 判断字符串是否由数字所组成 * @param temp 要判断的字符串数据 * @return 如果字符串由数字组成返回true,否则返回false */ public static boolean isNumber(String temp) { char[] data = temp.toCharArray(); // 将字符串变为字符数组,可以取出每一位字符进行判断 for (int x = 0; x < data.length; x++) { // 循环判断 if (data[x] > '9' || data[x] < '0') { // 不是数字字符范围 return false; // 后续不再判断 } } return true; // 如果全部验证通过返回true } } |
范例1-48:观察字符串与字节数组的转换。
public class StringDemo { public static void main(String args[]) { String str = "helloworld"; // 定义字符串 byte[] data = str.getBytes(); // 将字符串变为字节数组 for (int x = 0; x < data.length; x++) { data[x] -= 32; // 将小写字母变为大写形式 } System.out.println(new String(data)); // 全部转换 System.out.println(new String(data, 5, 5)); // 部分转换 } } |
范例1-49:相等判断。
public class StringDemo { public static void main(String args[]) { String stra = "Hello"; // 实例化字符串对象 String strb = "hELLO"; // 实例化字符串对象 System.out.println(stra.equals(strb)); // 比较结果:false System.out.println(stra.equalsIgnoreCase(strb)); // 比较结果:true } } |
范例1-50:观察compareTo()方法。
public class StringDemo { public static void main(String args[]) { String stra = "Hello"; // 定义字符串对象 String strb = "HEllo"; // 定义字符串对象 System.out.println(stra.compareTo(strb)); // 32,大于0 if (stra.compareTo(strb) > 0) { // 可以利用大小等于0的方式来判断大小 System.out.println("大于"); } } } |
范例1-51:使用indexOf()等功能查找。
public class StringDemo { public static void main(String args[]) { String str = "helloworld"; // 实例化字符串对象 System.out.println(str.indexOf("world")); // 返回满足条件单词的第一个字母的索引 System.out.println(str.indexOf("l")); // 返回的是第一个查找到的子字符串位置 System.out.println(str.indexOf("l", 5)); // 从第6个元素开始查找子字符串位置 System.out.println(str.lastIndexOf("l")); // 从后向前开始查找指定字符串的位置 } } |
范例1-52:利用indexOf()方法判断子字符串是否存在。
public class StringDemo { public static void main(String args[]) { String str = "helloworld"; // 字符串对象 if (str.indexOf("world") != -1) { // 能找到子字符串 System.out.println("可以查询到数据。"); } } } |
范例1-53:使用contains()方法判断子字符串是否存在。
public class StringDemo { public static void main(String args[]) { String str = "helloworld"; // 字符串对象 if (str.contains("world")) { // 子字符串存在 System.out.println("可以查询到数据。"); } } } |
范例1-54:开头或结尾判断。
public class StringDemo { public static void main(String args[]) { String str = "##@@hello**"; // 字符串对象 System.out.println(str.startsWith("##")); // 是否以“##”开头 System.out.println(str.startsWith("@@", 2)); // 从第2个索引开始是否以“@@”开头 System.out.println(str.endsWith("**")); // 是否以“**”结尾 } } |
范例1-55:观察替换的结果。
public class StringDemo { public static void main(String args[]) { String str = "helloworld" ; // 定义字符串 String resultA = str.replaceAll("l","_") ; // 全部替换 String resultB = str.replaceFirst("l","_") ; // 替换首个 System.out.println(resultA) ; System.out.println(resultB) ; } } |
范例1-56:验证操作。
public class StringDemo { public static void main(String args[]) { String str = "helloworld"; // 定义字符串 String resultA = str.substring(5); // 从指定索引截取到结尾 String resultB = str.substring(0, 5); // 截取部分子字符串 System.out.println(resultA); System.out.println(resultB); } } |
范例1-57:进行全部拆分。
public class StringDemo { public static void main(String args[]) { String str = "hello yootk nihao mldn"; // 定义字符串,中间使用空格作为间隔 String result[] = str.split(" "); // 字符串拆分 for (int x = 0; x < result.length; x++) { // 循环输出 System.out.print(result[x] + "、"); } } } |
范例1-58:字符串全部拆分。
public class StringDemo { public static void main(String args[]) { String str = "hello yootk"; // 定义字符串 String result[] = str.split(""); // 字符串全部拆分 for (int x = 0; x < result.length; x++) { // 循环输出 System.out.print(result[x] + "、"); } } } |
范例1-59:拆分为指定的个数。
public class StringDemo { public static void main(String args[]) { String str = "hello yootk nihao mldn"; // 定义字符串,中间使用空格作为间隔 String result[] = str.split(" ",2); // 字符串拆分 for (int x = 0; x < result.length; x++) { // 循环输出 System.out.println(result[x]); } } } |
范例1-60:错误的拆分操作。
public class StringDemo { public static void main(String args[]) { String str = "192.168.1.2"; // 定义字符串 String result[] = str.split("."); // 字符串拆分 for (int x = 0; x < result.length; x++) { // 循环输出 System.out.print(result[x] + "、"); } } } |
范例1-61:正常的拆分操作。
public class StringDemo { public static void main(String args[]) { String str = "192.168.1.2"; // 定义字符串 String result[] = str.split("\\."); // 字符串拆分 for (int x = 0; x < result.length; x++) { // 循环输出 System.out.print(result[x] + "、"); } } } |
范例1-62:复杂拆分。
public class StringDemo { public static void main(String args[]) { String str = "张三:20|李四:21|王五:22"; // 定义字符串 String result[] = str.split("\\|"); // 第一次拆分 for (int x = 0; x < result.length; x++) { String temp[] = result[x].split(":"); // 第二次拆分 System.out.println("姓名:" + temp[0] + ",年龄:" + temp[1]); } } } |
范例1-63:字符串连接。
public class StringDemo { public static void main(String args[]) { String str = "hello".concat("world") ; // 等价于“+” System.out.println(str) ; } } |
范例1-64:转小写与转大写操作。
public class StringDemo { public static void main(String args[]) { String str = "(*(*Hello(*(*" ; // 定义字符串 System.out.println(str.toUpperCase()) ; // 转大写后输出 System.out.println(str.toLowerCase()) ; // 转小写后输出 } } |
范例1-65:去掉左右空格。
public class StringDemo { public static void main(String args[]) { String str = " hello world "; // 定义字符串,包含空格 System.out.println("【" + str + "】"); // 原始字符串 System.out.println("【" + str.trim() + "】"); // 去掉空格后的字符串 } } |
范例1-66:取消掉全部空格。
public class StringDemo { public static void main(String args[]) { String str = " hello world "; // 定义字符串,包含空格 System.out.println(str.replaceAll(" ","")); // 去掉空格后的字符串 } } |
范例1-67:取得字符串长度。
public class StringDemo { public static void main(String args[]) { String str = "helloworld"; // 定义字符串 System.out.println(str.length()); // 取得字符串长度 } } |
范例1-68:判断是否为空字符串。
public class StringDemo { public static void main(String args[]) { String str = "helloworld"; // 定义字符串 System.out.println(str.isEmpty()); // 判断字符串对象的内容是否为空字符串(不是null) System.out.println("".isEmpty()); // 判断字符串常量的内容是否为空字符串(不是null) } } |
范例1-69:实现首字母大写的操作。
public class StringDemo { public static void main(String args[]) { String str = "yootk"; // 定义字符串 System.out.println(initcap(str)); // 调用initcap()方法 } /** * 实现首字母大写的操作 * @param temp 要转换的字符串数据 * @return 将首字母大写后返回 */ public static String initcap(String temp) { // 利用substring(0,1)取出字符串的第一位后将其变为大写,再连接剩余的字符串 return temp.substring(0, 1).toUpperCase() + temp.substring(1); } } |
1.10 this关键字
范例1-70:观察程序问题。
class Book { private String title; private double price; public Book(String title, double price) { title = title; // 原本的目的是希望将构造方法中的title变量内容设置给title属性 price = price; // 原本的目的是希望将构造方法中的price变量内容设置给price属性 } // setter、getter略 public String getInfo() { return "书名:" + title + ",价格:" + price; } } public class TestDemo { public static void main(String args[]) { Book book = new Book("Java开发", 89.2); System.out.println(book.getInfo()); } } |
范例1-71:使用this关键字明确地表示访问类中的属性。
class Book { private String title; private double price; public Book(String title, double price) { this.title = title; // this.属性表示的是本类属性,这样即使与方法中的参数重名也可以明确定位 this.price = price; // this.属性表示的是本类属性,这样即使与方法中的参数重名也可以明确定位 } // setter、getter略 public String getInfo() { return "书名:" + title + ",价格:" + price; } } public class TestDemo { public static void main(String args[]) { Book book = new Book("Java开发", 89.2); System.out.println(book.getInfo()); } } |
范例1-72:调用本类普通方法。
class Book { private String title; private double price; public Book(String title, double price) { this.title = title; this.price = price; } public void print() { System.out.println("更多课程请访问:www.yootk.com") ; } // setter、getter略 public String getInfo() { this.print() ; // 调用本类方法 return "书名:" + title + ",价格:" + price; } } public class TestDemo { public static void main(String args[]) { Book book = new Book("Java开发", 89.2); System.out.println(book.getInfo()); } } |
范例1-73:观察程序问题。
class Book { private String title; private double price; public Book() { System.out.println("一个新的Book类对象产生。"); // 把这行语句想象成50行代码 } public Book(String title) { System.out.println("一个新的Book类对象产生。"); // 把这行语句想象成50行代码 this.title = title; } public Book(String title, double price) { System.out.println("一个新的Book类对象产生。"); // 把这行语句想象成50行代码 this.title = title; this.price = price; } // setter、getter略 public String getInfo() { return "书名:" + this.title + ",价格:" + this.price; } } public class TestDemo { public static void main(String args[]) { Book book = new Book("Java开发", 89.2); System.out.println(book.getInfo()); } } |
范例1-74:消除掉构造方法中的重复代码。
class Book { private String title; private double price; public Book() { System.out.println("一个新的Book类对象产生。"); // 把这行语句想象成50行代码 } public Book(String title) { this() ; // 调用本类无参构造方法 this.title = title; } public Book(String title, double price) { this(title) ; // 调用本类有一个参数的构造方法 this.price = price; } // setter、getter略 public String getInfo() { return "书名:" + this.title + ",价格:" + this.price; } } public class TestDemo { public static void main(String args[]) { Book book = new Book("Java开发", 89.2); System.out.println(book.getInfo()); } } |
范例1-75:观察错误的代码。
class Book { private String title; private double price; public Book() { this("HELLO", 1.1); // 调用双参构造 System.out.println("一个新的Book类对象产生。"); } public Book(String title) { this(); // 调用本类的无参构造 this.title = title; } public Book(String title, double price) { this(title); // 调用本类的单参构造 this.price = price; } // setter、getter略 public String getInfo() { return "书名:" + this.title + ",价格:" + this.price; } } |
范例1-76:直接输出对象。
class Book { public void print() { // 调用print()方法的对象就是当前对象,this就自动与此对象指向同一块内存地址 System.out.println("this = " + this); // this就是当前调用方法的对象 } } public class TestDemo { public static void main(String args[]) { Book booka = new Book(); // 实例化新的Book类对象 System.out.println("booka = " + booka); // 主方法中输出Book类对象 booka.print(); // 调用Book类的print()方法输出,此时booka为当前对象 System.out.println("---------------------------"); Book bookb = new Book(); // 实例化新的Book类对象 System.out.println("bookb = " + bookb); // 主方法中输出Book类对象 bookb.print(); // 调用Book类的print()方法输出,此时bookb为当前对象 } } |
1.11 引用传递
范例1-77:第一道引用传递范例。
class Message { private int num = 10; // 定义int基本类型的属性 /** * 本类没有提供无参构造方法,而是提供有参构造,可以接收num属性的内容 * @param num 接收num属性的内容 */ public Message(int num) { this.num = num; // 为num属性赋值 } public void setNum(int num) { this.num = num; } public int getNum() { return this.num; } } public class TestDemo { public static void main(String args[]) { Message msg = new Message(30); // 实例化Message类对象同时传递num属性内容 fun(msg); // 引用传递 System.out.println(msg.getNum()); // 输出num属性内容 } /** * 修改Message类中的num属性内容 * @param temp Message类的引用 */ public static void fun(Message temp) { temp.setNum(100); // 修改num属性内容 } } |
范例1-78:第二道引用范例。
public class TestDemo { public static void main(String args[]) { String msg = "Hello"; // 定义String类对象 fun(msg); // 引用传递 System.out.println(msg); // 输出msg对象内容 } public static void fun(String temp) { // 接收字符串引用 temp = "World"; // 改变字符串引用 } } |
范例1-79:实现int数据的接收。
public class TestDemo { public static void main(String args[]) { int msg = 10 ; // 基本数据类型 fun(msg); // 数值传递 System.out.println(msg); // 输出msg变量内容 } public static void fun(int temp) { // 接收数据内容 temp = 100; // 改变变量内容 } } |
范例1-80:第三道引用传递。
class Message { private String info = "此内容无用" ; // 定义String类型属性 public Message(String info) { // 利用构造方法设置info属性内容 this.info = info ; } public void setInfo(String info) { this.info = info ; } public String getInfo() { return this.info ; } } public class TestDemo { public static void main(String args[]) { Message msg = new Message("Hello") ; // 实例化Message类对象 fun(msg) ; // 引用传递 System.out.println(msg.getInfo()) ; // 输出info属性内容 } public static void fun(Message temp) { // 接收Message类引用 temp.setInfo("World") ; // 修改info属性内容 } } |
范例1-81:数据库创建脚本。
CREATE TABLE member( mid NUMBER , name VARCHAR2(50) , CONSTRAINT pk_mid PRIMARY KEY(mid) ) ; CREATE TABLE car( mid NUMBER , pname VARCHAR2(50) , CONSTRAINT fk_mid FOREIGN KEY(mid) REFERENCES member(mid) , CONSTRAINT pk_mid2 PRIMARY KEY(mid) ) ; |
范例1-82:代码实现(无参构造、setter、getter略,同时本程序定义的是两个简单Java类)。
class Member { private int mid; // 人员编号 private String name; // 人员姓名 private Car car; // 表示属于人的车,如果没有车则内容为null public Member(int mid, String name) { this.mid = mid; this.name = name; } public void setCar(Car car) { this.car = car ; } public Car getCar() { return this.car ; } public String getInfo() { return "人员编号:" + this.mid + ",姓名:" + this.name; } } class Car { private Member member; // 车属于一个人,如果没有所属者,则为null private String pname; // 车的名字 public Car(String pname) { this.pname = pname; } public void setMember(Member member) { this.member = member ; } public Member getMember() { return this.member ; } public String getInfo() { return "车的名字:" + this.pname; } } |
范例1-83:代码测试。
public class TestDemo { public static void main(String args[]) { // 第一步:根据既定结构设置数据 Member m = new Member(1,"李兴华") ; // 独立对象 Car c = new Car("八手奥拓100") ; // 独立对象 m.setCar(c) ; // 一个人有一辆车 c.setMember(m) ; // 一辆车属于一个人 // 第二步:根据既定结构取出关系 System.out.println(m.getCar().getInfo()) ; // 通过人找到车的信息 System.out.println(c.getMember().getInfo()) ; // 通过车找到人的信息 } } |
范例1-84:修改Member类定义。
class Member { private int mid; // 人员编号 private String name; // 人员姓名 private Car car; // 表示属于人的车,如果没有车,则内容为null private Member child ; // 表示人的孩子,如果没有,则为null public Member(int mid, String name) { this.mid = mid; this.name = name; } public void setCar(Car car) { this.car = car ; } public Car getCar() { return this.car ; } public void setChild(Member child) { this.child = child; } public Member getChild() { return child; } public String getInfo() { return "人员编号:" + this.mid + ",姓名:" + this.name; } } class Car { private Member member; // 车属于一个人,如果没有所属者,则为null private String pname; // 车的名字 public Car(String pname) { this.pname = pname; } public void setMember(Member member) { this.member = member ; } public Member getMember() { return this.member ; } public String getInfo() { return "车的名字:" + this.pname; } } public class TestDemo { public static void main(String args[]) { // 第一步:根据既定结构设置数据 Member m = new Member(1,"李兴华") ; // 独立对象 Member chd = new Member(2,"李闯") ; // 独立对象 Car c = new Car("八手奥拓100") ; // 独立对象 Car cc = new Car("法拉利M9") ; // 一辆车 m.setCar(c) ; // 一个人有一辆车 c.setMember(m) ; // 一辆车属于一个人 chd.setCar(cc) ; // 一个孩子有一辆车 cc.setMember(chd) ; // 一个车属于一个孩子 m.setChild(chd) ; // 一个人有一个孩子 // 第二步:根据既定结构取出关系 System.out.println(m.getCar().getInfo()) ; // 通过人找到车的信息 System.out.println(c.getMember().getInfo()) ; // 通过车找到人的信息 System.out.println(m.getChild().getInfo()) ; // 通过人找到他孩子的信息 System.out.println(m.getChild().getCar().getInfo()) ; // 通过人找到他孩子的车的信息 } } |
范例1-85:描述电脑组成关系。
class 键盘{} class 鼠标{} class CPU{} class 硬盘{} class 内存{} class 显示器{} class 主板 {} class 主机 { private CPU 对象1 [] ; private 硬盘 对象2 [] ; private 主板 对象3 ; private 内存 对象4 [] ; } class 计算机 { private 主机 对象1 ; private 显示器 对象2 [] ; private 键盘 对象3 ; private 鼠标 对象4 ; } |
1.12 数据表与简单Java类映射
范例1-86:代码实现。
class Dept { private int deptno; // 部门编号 private String dname; // 部门名称 private String loc; // 部门位置 private Emp emps [] ; // 多个雇员 public Dept(int deptno, String dname, String loc) { this.deptno = deptno; this.dname = dname; this.loc = loc; } // setter、getter、无参构造略 public String getInfo() { return "部门编号:" + this.deptno + ",名称:" + this.dname + ",位置:" + this.loc; } } class Emp { private int empno; // 雇员编号 private String ename; // 雇员姓名 private String job; // 雇员职位 private double sal; // 基本工资 private double comm; // 佣金 private Dept dept ; private Emp mgr; // 表示雇员对应的领导 public Emp(int empno, String ename, String job, double sal, double comm) { this.empno = empno; this.ename = ename; this.job = job; this.sal = sal; this.comm = comm; } // setter、getter、无参构造略 public String getInfo() { return "雇员编号:" + this.empno + ",姓名:" + this.ename + ",职位:" + this.job + ",工资:" + this.sal + ",佣金:" + this.comm; } } |
范例1-87:设置并取得数据。
public class TestDemo { public static void main(String args[]) { // 第一步:根据表结构描述设置数据 // 1.产生各自的独立对象 Dept dept = new Dept(10,"ACCOUNTING","New York") ; // 部门信息 Emp ea = new Emp(7369,"SMITH","CLERK",800.0,0.0) ; // 雇员信息 Emp eb = new Emp(7902,"FORD","MANAGER",2450.0,0.0) ; // 雇员信息 Emp ec = new Emp(7839,"KING","PRESIDENT",5000.0,0.0) ; // 雇员信息 // 2.设置雇员和领导关系 ea.setMgr(eb) ; // 设置雇员领导 eb.setMgr(ec) ; // 设置雇员领导 // 3.设置雇员和部门关系 ea.setDept(dept) ; // 雇员与部门 eb.setDept(dept) ; // 雇员与部门 ec.setDept(dept) ; // 雇员与部门 dept.setEmps(new Emp[]{ea,eb,ec}) ; // 部门与雇员 // 第二步:根据表结构描述取得设置的数据 System.out.println(ea.getInfo()) ; // 取得雇员信息 System.out.println("\t|- " + ea.getMgr().getInfo()) ; // 取得雇员领导信息 System.out.println("\t|- " + ea.getDept().getInfo()) ; // 取得雇员部门信息 // 取得部门的完整信息,包括部门基础信息以及部门中的所有员工和每个员工的领导信息 System.out.println(dept.getInfo()) ; // 部门信息 for (int x = 0 ; x < dept.getEmps().length ; x ++) { // 所有雇员信息 System.out.println("\t|- " + dept.getEmps()[x].getInfo()) ; // 雇员信息 if (dept.getEmps()[x].getMgr() != null) { // 判断是否存在领导信息 System.out.println("\t\t|- " + dept.getEmps()[x].getMgr().getInfo()); // 领导信息 } } } } |
1.13 对象比较
范例1-88:基础的比较方式。
class Book { private String title; private double price; public Book(String title, double price) { this.title = title; this.price = price; } public String getTitle() { return this.title; } public double getPrice() { return this.price; } } public class TestDemo { public static void main(String args[]) { Book b1 = new Book("Java开发", 79.8); // 实例化Book类对象 Book b2 = new Book("Java开发", 79.8); // 实例化Book类对象 if (b1.getTitle().equals(b2.getTitle()) && b1.getPrice() == b2.getPrice()) { // 属性比较 System.out.println("是同一个对象!"); } else { System.out.println("不是同一个对象!"); } } } |
范例1-89:观察封装属性的进一步操作。
class Info { private String msg = "Hello"; public void print() { System.out.println("msg = " + msg); } public void fun(Info temp) { // 本类接收本类对象 temp.msg = "修改内容"; // 在类的内部直接利用对象访问私有属性 } } public class Demo { public static void main(String args[]) { Info x = new Info(); x.fun(x); // 没有意义,只是一个语法验证 x.print(); } } |
范例1-90:对象比较实现。
class Book { private String title ; private double price ; public Book(String title,double price) { this.title = title ; this.price = price ; } /** * 进行本类对象的比较操作,在比较过程中首先会判断传入的对象是否为null,然后判断地址是否相同 * 如果都不相同则进行对象内容的判断,由于compare()方法接收了本类引用,所以可以直接访问私有属性 * @param book 要进行判断的数据 * @return 内存地址相同或者属性完全相同返回true,否则返回false */ public boolean compare(Book book) { if (book == null) { // 传入数据为null return false ; // 没有必要进行具体的判断 } // 执行“b1.compare(b2)”代码时会有两个对象 // 当前对象this(调用方法对象,就是b1引用) // 传递的对象book(引用传递,就是b2引用) if (this == book) { // 内存地址相同 return true ; // 避免进行具体细节的比较,节约时间 } if (this.title.equals(book.title) && this.price == book.price) { // 属性判断 return true ; } else { return false ; } } // setter、getter略 } public class TestDemo { public static void main(String args[]) { Book b1 = new Book("Java开发",79.8) ; // 实例化Book类对象 Book b2 = new Book("Java开发",79.8) ; // 实例化Book类对象 if (b1.compare(b2)) { // 对象比较 System.out.println("是同一个对象!") ; } else { System.out.println("不是同一个对象!") ; } } } |
1.14 static关键字
范例1-91:定义程序。
class Book { // 描述的是同一个出版社的信息 private String title ; // 普通属性 private double price ; // 普通属性 static String pub = "清华大学出版社" ; // 定义一个描述出版社信息的属性,为操作方便,暂不封装 public Book(String title,double price) { this.title = title ; this.price = price ; } public String getInfo() { return "图书名称:" + this.title + ",价格:" + this.price + ",出版社:" + this.pub ; } } public class TestDemo { public static void main(String args[]) { Book ba = new Book("Java开发",10.2) ; // 实例化Book类对象 Book bb = new Book("Android开发",11.2) ; // 实例化Book类对象 Book bc = new Book("Oracle开发",12.2) ; // 实例化Book类对象 ba.pub = "北京大学出版社" ; // 修改了一个属性的内容 System.out.println(ba.getInfo()) ; System.out.println(bb.getInfo()) ; System.out.println(bc.getInfo()) ; } } |
范例1-92:在没有实例化对象产生时直接操作static属性。
public class TestDemo { public static void main(String args[]) { System.out.println(Book.pub) ; // 在没有实例化对象的情况下直接输出属性内容 Book.pub = "北京大学出版社" ; // 修改static属性内容 Book ba = new Book("Java开发",10.9) ; // 实例化Book类对象 System.out.println(ba.getInfo()) ; // 输出Book类对象信息 } } |
范例1-93:使用static定义方法。
class Book { // 描述的是同一个出版社的信息 private String title ; private double price ; private static String pub = "清华大学出版社" ; // 定义一个描述出版社信息的属性 public Book(String title,double price) { this.title = title ; this.price = price ; } public static void setPub(String p) { // 定义static方法可以由类名称直接调用 pub = p ; } public String getInfo() { return "图书名称:" + this.title + ",价格:" + this.price + ",出版社:" + this.pub ; } } public class TestDemo { public static void main(String args[]) { Book.setPub("北京大学出版社") ; // 在没有对象产生的时候进行调用 Book ba = new Book("Java开发",10.2) ; // 实例化Book类对象 Book bb = new Book("Android开发",11.2) ; // 实例化Book类对象 Book bc = new Book("Oracle开发",12.2) ; // 实例化Book类对象 System.out.println(ba.getInfo()) ; System.out.println(bb.getInfo()) ; System.out.println(bc.getInfo()) ; } } |
范例1-94:观察如下代码。
public class TestDemo { public static void main(String args[]) { // static定义的方法 fun(); // static方法调用static方法 } public static void fun() { // static定义的方法 System.out.println("Hello World !"); } } |
范例1-95:不使用static声明方法。
public class TestDemo { public static void main(String args[]) { // static定义的方法 new TestDemo().fun(); // 对象调用方法 } public void fun() { // 非static定义的方法 System.out.println("Hello World !"); } } |
范例1-96:定义一个数学的加法操作。
class MyMath { // 数学操作类,类中没有属性 public static int add(int x, int y) { // 只是一个加法操作 return x + y; } } public class TestDemo { public static void main(String args[]) { System.out.println(MyMath.add(10, 20)); // 直接调用 } } |
范例1-97:得到参数。
public class TestDemo { public static void main(String args[]) { for (int x = 0; x < args.length; x++) { // 循环输出参数 System.out.println(args[x]); } } } |
1.15 代码块
范例1-98:编写普通代码块。
public class TestDemo { public static void main(String args[]) { { // 普通代码块 int num = 10; // 局部变量 System.out.println("num = " + num); } int num = 100; // 全局变量 System.out.println("num = " + num); } } |
范例1-99:说明代码。
public class TestDemo { private static int num = 100 ; // 全局变量 public static void main(String args[]) { int num = 100; // 局部变量 } } |
范例1-100:定义构造块。
class Book { public Book() { // 构造方法 System.out.println("【A】Book类的构造方法"); } { // 将代码块写在类里,所以为构造块 System.out.println("【B】Book类中的构造块"); } } public class TestDemo { public static void main(String args[]) { new Book(); // 实例化类对象 new Book(); // 实例化类对象 } } |
范例1-101:利用静态块为static属性初始化。
class Book { static String msg ; // static属性,暂不封装 public Book() { // 构造方法 System.out.println("【A】Book类的构造方法"); } { // 将代码块写在类里,所以为构造块 System.out.println("【B】Book类中的构造块"); } static { // 定义静态块 msg = "Hello".substring(0,2) ; System.out.println("【C】Book类中的静态块") ; } } public class TestDemo { public static void main(String args[]) { new Book(); // 实例化类对象 new Book(); // 实例化类对象 System.out.println(Book.msg) ; } } |
范例1-102:JDK 1.7之前的Bug。
public class TestDemo { static { System.out.println("Hello World ."); System.exit(1); } } |
1.16 内部类
范例1-103:观察内部类的基本形式。
class Outer { // 外部类 private String msg = "Hello World !"; class Inner { // 定义一个内部类 public void print() { System.out.println(msg); } } public void fun() { new Inner().print(); // 实例化内部类对象,并且调用print()方法 } } public class TestDemo { public static void main(String args[]) { Outer out = new Outer(); // 实例化外部类对象 out.fun(); // 调用外部类方法 } } |
范例1-104:将内部类放到外部并且实现同样功能。
class Outer { // 外部类 private String msg = "Hello World !" ; public void fun() { // this表示当前调用fun()方法的对象,在本程序中主方法由out对象调用,所以this就是out new Inner(this).print() ; // 实例化内部类对象,并且调用print()方法 } // 内部类需要访问msg属性,但是此属性属于Outer类,而在Outer类里面此属性使用private进行封装 // 所以如果此时要得到这个属性的内容,需要定义一个getter方法 public String getMsg() { return this.msg ; } } class Inner { // 定义一个内部类 private Outer out ; // 必须依靠对象才可以调用getMsg()方法 public Inner(Outer out) { // 在构造方法中接收外部类对象 this.out = out ; } public void print() { // 利用Outer类对象调用方法 System.out.println(this.out.getMsg()) ; } } public class TestDemo { public static void main(String args[]) { Outer out = new Outer() ; // 实例化外部类对象 out.fun() ; // 调用外部类方法 } } |
范例1-105:访问内部类的私有属性。
class Outer { // 外部类 private String msg = "Hello World !" ; class Inner { // 定义一个内部类 private String info = "世界,你好!" ; // 内部类的私有属性 public void print() { System.out.println(msg) ; // 直接访问外部类的私有属性 } } public void fun() { Inner in = new Inner() ; // 内部类对象 System.out.println(in.info) ; // 直接利用内部类对象访问内部类中定义的私有属性 } } public class TestDemo { public static void main(String args[]) { Outer out = new Outer() ; // 实例化外部类对象 out.fun() ; // 调用外部类方法 } } |
范例1-106:使用this访问外部类属性。
class Outer { // 外部类 private String msg = "Hello World !" ; class Inner { // 定义一个内部类 public void print() { System.out.println(Outer.this.msg) ; // 外部类.this = 外部类当前对象 } } } |
范例1-107:实例化内部类对象。
class Outer { // 外部类 private String msg = "Hello World !" ; class Inner { // 定义一个内部类 public void print() { System.out.println(Outer.this.msg) ; } } } public class TestDemo { public static void main(String args[]) { Outer.Inner in = new Outer().new Inner() ; // 实例化内部类对象 in.print() ; } } |
范例1-108:定义私有内部类
class Outer { // 外部类 private String msg = "Hello World !" ; private class Inner { // 定义私有内部类 public void print() { System.out.println(Outer.this.msg) ; } } } |
范例1-109:利用static定义内部类。
class Outer { // 外部类 private static String msg = "Hello World !"; // static属性 static class Inner { // static定义的内部类等同于外部类 public void print() { System.out.println(Outer.msg); // 直接访问static属性 } } } |
范例1-110:实例化“外部类”对象。
class Outer { // 外部类 private static String msg = "Hello World !"; // static属性 static class Inner { // static定义的内部类等同于外部类 public void print() { System.out.println(Outer.msg); // 直接访问static属性 } } } public class TestDemo { public static void main(String args[]) { Outer.Inner in = new Outer.Inner() ; // 实例化“外部类”对象 in.print() ; // 调用方法 } } |
范例1-111:在普通方法里面定义内部类。
class Outer { // 外部类 private String msg = "Hello World !" ; public void fun() { // 外部类普通方法 class Inner { // 方法中定义的内部类 public void print() { System.out.println(Outer.this.msg) ; } } new Inner().print() ; // 内部类实例化对象调用print()输出 } } public class TestDemo { public static void main(String args[]) { new Outer().fun() ; } } |
范例1-112:访问方法中定义的参数或变量。
class Outer { // 外部类 private String msg = "Hello World !" ; public void fun(int num) { // 外部类普通方法 double score = 99.9 ; // 方法变量 class Inner { // 方法中定义的内部类 public void print() { System.out.println("属性:" + Outer.this.msg) ; System.out.println("方法参数:" + num) ; System.out.println("方法变量:" + score) ; } } new Inner().print() ; // 内部类实例化对象调用print()输出 } } public class TestDemo { public static void main(String args[]) { new Outer().fun(100) ; } } |
范例1-113:JDK 1.7之前的代码。
class Outer { // 外部类 private String msg = "Hello World !" ; public void fun(final int num) { // 外部类普通方法 final double score = 99.9 ; // 方法变量 class Inner { // 方法中定义的内部类 public void print() { System.out.println("属性:" + Outer.this.msg) ; System.out.println("方法参数:" + num) ; System.out.println("方法变量:" + score) ; } } new Inner().print() ; // 内部类实例化对象调用print()输出 } } |
1.17 链表
范例1-114:定义一个Node类。
class Node { // 每一个链表实际上就是由多个节点组成的 private String data; // 要保存的数据 private Node next; // 要保存的下一个节点 /** * 每一个Node类对象都必须保存有相应的数据 * @param data 要通过节点包装的数据 */ public Node(String data) { // 必须有数据才有Node this.data = data; } /** * 设置下一个节点关系 * @param next 保存下一个Node类引用 */ public void setNext(Node next) { this.next = next; } /** * 取得当前节点的下一个节点 * @return 当前节点的下一个节点引用 */ public Node getNext() { return this.next; } /** * 设置或修改当前节点包装的数据 * @param data */ public void setData(String data) { this.data = data; } /** * 取得包装的数据 * @return */ public String getData() { return this.data; } } |
范例1-115:手工配置节点关系,并使用while循环输出全部节点数据。
public class LinkDemo { public static void main(String args[]) { // 第一步:定义要操作的节点并设置好包装的字符串数据 Node root = new Node("火车头") ; // 定义节点,同时包装数据 Node n1 = new Node("车厢A") ; // 定义节点,同时包装数据 Node n2 = new Node("车厢B") ; // 定义节点,同时包装数据 root.setNext(n1) ; // 设置节点关系 n1.setNext(n2) ; // 设置节点关系 // 第二步:根据节点关系取出所有数据 Node currentNode = root ; // 当前从根节点开始读取 while (currentNode != null) { // 当前节点存在数据 System.out.println(currentNode.getData()) ; currentNode = currentNode.getNext() ; // 将下一个节点设置为当前节点 } } } |
范例1-116:手工配置节点关系,通过递归输出全部节点数据。
public class LinkDemo { public static void main(String args[]) { // 第一步:定义要操作的节点并设置好包装的字符串数据 Node root = new Node("火车头") ; // 定义节点,同时包装数据 Node n1 = new Node("车厢A") ; // 定义节点,同时包装数据 Node n2 = new Node("车厢B") ; // 定义节点,同时包装数据 root.setNext(n1) ; // 设置节点关系 n1.setNext(n2) ; // 设置节点关系 print(root) ; // 由根节点开始输出 } /** * 利用递归方式输出所有的节点数据 * @param current */ public static void print(Node current) { // 第二步:根据节点关系取出所有数据 if (current == null) { // 递归结束条件 return; // 结束方法 } System.out.println(current.getData()); // 输出节点包含的数据 print(current.getNext()); // 递归操作 } } |
范例1-117:链表的基本形式。
class Node { // 定义一个节点 private String data; // 要保存的数据 private Node next; // 要保存的下一个节点 public Node(String data) { // 每一个Node类对象都必须保存相应的数据 this.data = data; } public void setNext(Node next) { this.next = next; } public Node getNext() { return this.next; } public String getData() { return this.data; } /** * 实现节点的添加(递归调用,目的是将新节点保存到最后一个节点之后) * 第一次调用(Link):this = Link.root * 第二次调用(Node):this = Link.root.next * 第三次调用(Node):this = Link.root.next.next * @param newNode 新节点,节点对象由Link类创建 */ public void addNode(Node newNode) { if (this.next == null) { // 当前节点的下一个为null this.next = newNode; // 保存新节点 } else { // 当前节点之后还存在节点 this.next.addNode(newNode); // 当前节点的下一个节点继续保存 } } /** * 递归的方式输出每个节点保存的数据 * 第一次调用(Link):this = Link.root * 第二次调用(Node):this = Link.root.next * 第三次调用(Node):this = Link.root.next.next */ public void printNode() { System.out.println(this.data); // 输出当前节点数据 if (this.next != null) { // 还有下一个节点 this.next.printNode(); // 找到下一个节点继续输出 } } } class Link { // 负责数据的设置和输出 private Node root; // 根节点 /** * 向链表中增加新的数据,如果当前链表没有节点则将第一个数据作为节点 * 如果有节点则使用Node类将新节点保存到最后一个节点之后 * @param data 要保存的数据 */ public void add(String data) { Node newNode = new Node(data); // 设置数据的先后关系,所以将data包装在一个Node类对象中 if (this.root == null) { // 一个链表只有一个根节点 this.root = newNode; // 将新的节点设置为根节点 } else { // 根节点已经存在 this.root.addNode(newNode); // 交由Node类来进行节点保存 } } /** * 使用递归方式,输出节点中的全部数据 */ public void print() { // 输出数据 if (this.root != null) { // 存在根节点 this.root.printNode(); // 交给Node类输出 } } } public class LinkDemo { public static void main(String args[]) { Link link = new Link(); // 由这个类负责所有的数据操作 link.add("Hello"); // 存放数据 link.add("MLDN"); // 存放数据 link.add("YOOTK"); // 存放数据 link.add("李兴华"); // 存放数据 link.print(); // 展示数据 } } |
范例1-118:链表的基本开发结构。
class Link { // 链表类,外部能够看见的只有这一个类 private class Node { // 定义的内部节点类 private String data; // 要保存的数据 private Node next; // 下一个节点引用 public Node(String data) { // 每一个Node类对象都必须保存相应的数据 this.data = data; } } // ===================== 以上为内部类 =================== private Node root; // 根节点定义 } |
范例1-119:修改Link.java类。
— 增加一个count属性,保存元素个数;
private int count = 0 ; // 保存元素的个数 |
— 在add()方法里面增加数据的统计操作;
/** * 用户向链表增加新的数据,在增加时要将数据封装为Node类,这样才可以匹配节点顺序 * @param data 要保存的数据 */ public void add(String data) { // 假设不允许有null if (data == null) { // 判断数据是否为空 return; // 结束方法调用 } Node newNode = new Node(data); // 要保存的数据 if (this.root == null) { // 当前没有根节点 this.root = newNode; // 保存根节点 } else { // 根节点存在 this.root.addNode(newNode); // 交给Node类处理节点的保存 } this.count ++ ; // 数据保存成功后保存个数加一 } |
— 随后为Link类增加一个新的方法:size()。
/** * 取得链表中保存的数据个数 * @return 保存的个数,通过count属性取得 */ public int size() { // 取得保存的数据量 return this.count; } |
范例1-120:判断是否为空链表。
/** * 判断是否是空链表,表示长度为0,不是null * @return 如果链表中没有保存任何数据则返回true,否则返回false */ public boolean isEmpty() { return this.count == 0; } |
范例1-121:在Node类增加方法。
/** * 数据检索操作,判断指定数据是否存在 * 第一次调用(Link):this = Link.root * 第二次调用(Node):this = Link.root.next * @param data 要查询的数据 * @return 如果数据存在返回true,否则返回false */ public boolean containsNode(String data) { if (data.equals(this.data)) { // 当前节点数据为要查询的数据 return true; // 后面不再查询 } else { // 当前节点数据不满足查询要求 if (this.next != null) { // 有后续节点 return this.next.containsNode(data); // 递归调用继续查询 } else { // 没有后续节点 return false; // 没有查询到返回false }
} |
范例1-122:修改Link。
/** * 数据查询操作,判断指定数据是否存在,如果链表没有数据直接返回false * @param data 要判断的数据 * @return 数据存在返回true,否则返回false */ public boolean contains(String data) { if (data == null || this.root == null) { // 现在没有要查询的数据,根节点也不保存数据 return false ; // 没有查询结果 } return this.root.containsNode(data) ; // 交由Node类查询 } |
范例1-123:定义测试程序。
public class LinkDemo { public static void main(String args[]) { Link all = new Link(); // 创建链表对象 all.add("yootk"); // 保存数据 all.add("mldn"); // 保存数据 System.out.println(all.contains("yootk")) ; System.out.println(all.contains("hello")) ; } } |
范例1-124:在Link类里面增加一个foot的属性,表示每一个Node元素的编号。
private int foot = 0 ; // 节点索引 |
范例1-125:在每一次查询时(一个链表可能查询多次),foot应该都从头开始计算(foot设为0)。
/** * 根据索引取得保存的节点数据 * @param index 索引数据 * @return 如果要取得的索引内容不存在或者大于保存个数返回null,反之返回数据 */ public String get(int index) { if (index > this.count) { // 超过了查询范围 return null ; // 没有数据 } this.foot = 0 ; // 表示从前向后查询 return this.root.getNode(index) ; // 查询过程交给Node类 } |
范例1-126:在Node类里面实现getNode()方法,内部类和外部类之间可以方便地进行私有属性的互相访问。
/** * 根据索引取出数据,此时该索引一定是存在的 * @param index 要取得数据的索引编号 * @return 返回指定索引节点包含的数据 */ public String getNode(int index) { // 使用当前的foot内容与要查询的索引进行比较,随后将foot的内容自增,目的是下次查询方便 if (Link.this.foot++ == index) { // 当前为要查询的索引 return this.data; // 返回当前节点数据 } else { // 继续向后查询 return this.next.getNode(index); // 进行下一个节点的判断 } } |
范例1-127:在Node类里面增加setNode()方法。
/** * 修改指定索引节点包含的数据 * @param index 要修改的索引编号 * @param data 新数据 */ public void setNode(int index, String data) { // 使用当前的foot内容与要查询的索引进行比较,随后将foot的内容自增,目的是下次查询方便 if (Link.this.foot++ == index) { // 当前为要修改的索引 this.data = data; // 进行内容的修改 } else { this.next.setNode(index, data); // 继续下一个节点的索引判断 } } |
范例1-128:在Link类里面增加set()方法。
/** * 根据索引修改数据 * @param index 要修改数据的索引编号 * @param data 新的数据内容 */ public void set(int index, String data) { if (index > this.count) { // 判断是否超过了保存范围 return; // 结束方法调用 } this.foot = 0; // 重新设置foot属性的内容,作为索引出现 this.root.setNode(index, data); // 交给Node类设置数据内容 } |
范例1-128:在Node类里面增加一个removeNode()方法,此方法专门负责处理非根节点的删除。
/** * 节点的删除操作,匹配每一个节点的数据,如果当前节点数据符合删除数据 * 则使用“当前节点上一节点.next = 当前节点.next”方式空出当前节点 * 第一次调用(Link): previous = Link.root、this = Link.root.next * 第二次调用(Node): previous = Link.root.next、this = Link.root.next.next * @param previous 当前节点的上一个节点 * @param data 要删除的数据 */ public void removeNode(Node previous, String data) { if (data.equals(this.data)) { // 当前节点为要删除节点 previous.next = this.next; // 空出当前节点 } else { // 应该向后继续查询 this.next.removeNode(this, data); // 继续下一个判断 } } |
范例1-129:在Link类里面增加根节点的判断。
/** * 链表数据的删除操作,在删除前要先使用contains()判断链表中是否存在指定数据 * 如果要删除的数据存在,则首先判断根节点的数据是否为要删除数据 * 如果是,则将根节点的下一个节点作为新的根节点 * 如果要删除的数据不是根节点数据,则将删除操作交由Node类的removeNode()方法完成 * @param data 要删除的数据 */ public void remove(String data) { if (this.contains(data)) { // 主要功能是判断数据是否存在 // 要删除数据是否是根节点数据,root是Node类的对象,此处直接访问内部类的私有操作 if (data.equals(this.root.data)) { // 根节点数据为要删除数据 this.root = this.root.next; // 空出当前根节点 } else { // 根节点数据不是要删除数据 // 此时根元素已经判断过了,从第二个元素开始判断,即第二个元素的上一个元素为根节点 this.root.next.removeNode(this.root, data); } this.count--; // 删除成功后个数要减少 } } |
范例1-130:修改Link类的定义。
— 增加一个返回的数组属性内容,之所以将其定义为属性,是因为内部类和外部类都可以访问;
private String [] retArray ; // 返回的数组 |
— 增加toArray()方法。
/** * 将链表中的数据转换为对象数组输出 * @return 如果链表没有数据返回null,如果有数据则将数据变为对象数组后返回 */ public String[] toArray() { if (this.root == null) { // 判断链表是否有数据 return null; // 没有数据返回null } this.foot = 0; // 脚标清零操作 this.retArray = new String[this.count]; // 根据保存内容开辟数组 this.root.toArrayNode(); // 交给Node类处理 return this.retArray; // 返回数组对象 } |
范例1-131:在Node类里面处理数组数据的保存。
/** * 将节点中保存的内容转化为对象数组 * 第一次调用(Link):this = Link.root; * 第二次调用(Node):this = Link.root.next */ public void toArrayNode() { Link.this.retArray[Link.this.foot++] = this.data; // 取出数据并保存在数组中 if (this.next != null) { // 有后续元素 this.next.toArrayNode(); // 继续下一个数据的取得 } } |
范例1-132:清空链表。
public void clear() { this.root = null; // 清空链表 this.count = 0; // 元素个数为0 } |
范例1-133:定义一个保存图书信息的类。
class Book { private String title ; private double price ; public Book(String title,double price) { this.title = title ; this.price = price ; } /** * 进行本类对象的比较操作,在比较过程中首先会判断传入的对象是否为null,而后判断地址是否相同 * 如果都不相同则进行对象内容的判断,由于compare()方法接收了本类引用,所以可以直接访问私有属性 * @param book 要进行判断的数据 * @return 内存地址相同或属性完全相同返回true,否则返回false */ public boolean compare(Book book) { if (book == null) { // 传入数据为null return false ; // 没有必要进行具体的判断 } // 执行“b1.compare(b2)”代码时会有两个对象 // 当前对象this(调用方法对象,就是b1引用) // 传递的对象book(引用传递,就是b2引用) if (this == book) { // 内存地址相同 return true ; // 避免进行具体细节的比较,节约时间 } if (this.title.equals(book.title) && this.price == book.price) { // 属性判断 return true ; } else { return false ; } } // setter、getter略 public String getInfo() { return "图书名称:" + this.title + ",图书价格:" + this.price ; } } |
范例1-134:修改链表实现(本代码主要是将之前的链表类中的String类型更换为Book类型,对象比较更换为compare()方法)。
class Link { // 链表类,外部能够看见的只有这一个类 private class Node { // 定义的内部节点类 private Book data; // 要保存的数据 private Node next; // 下一个节点引用 public Node(Book data) { // 每一个Node类对象都必须保存相应的数据 this.data = data; } /** * 设置新节点的保存,所有的新节点保存在最后一个节点之后 * @param newNode 新节点对象 */ public void addNode(Node newNode) { if (this.next == null) { // 当前的下一个节点为null this.next = newNode ; // 保存节点 } else { // 向后继续保存 this.next.addNode(newNode) ; } } /** * 数据检索操作,判断指定数据是否存在 * 第一次调用(Link):this = Link.root * 第二次调用(Node):this = Link.root.next * @param data 要查询的数据 * @return 如果数据存在返回true,否则返回false */ public boolean containsNode(Book data) { if (data.compare(this.data)) { // 当前节点数据为要查询的数据 return true; // 后面不再查询了 } else { // 当前节点数据不满足查询要求 if (this.next != null) { // 有后续节点 return this.next.containsNode(data); // 递归调用继续查询 } else { // 没有后续节点 return false; // 没有查询到返回false } } } /** * 根据索引取出数据,此时该索引一定是存在的 * @param index 要取得数据的索引编号 * @return 返回指定索引节点包含的数据 */ public Book getNode(int index) { // 使用当前的foot内容与要查询的索引进行比较,随后将foot的内容自增,目的是下次查询方便 if (Link.this.foot++ == index) { // 当前为要查询的索引 return this.data; // 返回当前节点数据 } else { // 继续向后查询 return this.next.getNode(index); // 进行下一个节点的判断 } } /** * 修改指定索引节点包含的数据 * @param index 要修改的索引编号 * @param data 新数据 */ public void setNode(int index, Book data) { // 使用当前的foot内容与要查询的索引进行比较,随后将foot的内容自增,目的是下次查询方便 if (Link.this.foot++ == index) { // 当前为要修改的索引 this.data = data; // 进行内容的修改 } else { this.next.setNode(index, data); // 继续下一个节点的索引判断 } } /** * 节点的删除操作,匹配每一个节点的数据,如果当前节点数据符合删除数据, * 则使用“当前节点上一节点.next = 当前节点.next”方式空出当前节点 * 第一次调用(Link):previous = Link.root、this = Link.root.next * 第二次调用(Node):previous = Link.root.next、this = Link.root.next.next * @param previous 当前节点的上一个节点 * @param data 要删除的数据 */ public void removeNode(Node previous, Book data) { if (data.compare(this.data)) { // 当前节点为要删除节点 previous.next = this.next; // 空出当前节点 } else { // 应该向后继续查询 this.next.removeNode(this, data); // 继续下一个判断 } } /** * 将节点中保存的内容转化为对象数组 * 第一次调用(Link):this = Link.root; * 第二次调用(Node):this = Link.root.next; */ public void toArrayNode() { Link.this.retArray[Link.this.foot++] = this.data; // 取出数据并保存在数组中 if (this.next != null) { // 有后续元素 this.next.toArrayNode(); // 继续下一个数据的取得 } } } // ===================== 以上为内部类 =================== private Node root; // 根节点定义 private int count = 0 ; // 保存元素的个数 private int foot = 0 ; // 节点索引 private Book [] retArray ; // 返回的数组 /** * 用户向链表增加新的数据,在增加时要将数据封装为Node类,这样才可以匹配节点顺序 * @param data 要保存的数据 */ public void add(Book data) { // 假设不允许有null if (data == null) { // 判断数据是否为空 return; // 结束方法调用 } Node newNode = new Node(data); // 要保存的数据 if (this.root == null) { // 当前没有根节点 this.root = newNode; // 保存根节点 } else { // 根节点存在 this.root.addNode(newNode); // 交给Node类处理节点的保存 } this.count ++ ; // 数据保存成功后保存个数加一 } /** * 取得链表中保存的数据个数 * @return 保存的个数,通过count属性取得 */ public int size() { // 取得保存的数据量 return this.count; } /** * 判断是否是空链表,表示长度为0,不是null * @return 如果链表中没有保存任何数据则返回true,否则返回false */ public boolean isEmpty() { return this.count == 0; } /** * 数据查询操作,判断指定数据是否存在,如果链表没有数据直接返回false * @param data 要判断的数据 * @return 数据存在返回true,否则返回false */ public boolean contains(Book data) { if (data == null || this.root == null) { // 现在没有要查询的数据,根节点也不保存数据 return false ; // 没有查询结果 } return this.root.containsNode(data) ; // 交由Node类查询 } /** * 根据索引取得保存的节点数据 * @param index 索引数据 * @return 如果要取得的索引内容不存在或者大于保存个数返回null,反之返回数据 */ public Book get(int index) { if (index > this.count) { // 超过了查询范围 return null ; // 没有数据 } this.foot = 0 ; // 表示从前向后查询 return this.root.getNode(index) ; // 查询过程交给Node类 } /** * 根据索引修改数据 * @param index 要修改数据的索引编号 * @param data 新的数据内容 */ public void set(int index, Book data) { if (index > this.count) { // 判断是否超过了保存范围 return; // 结束方法调用 } this.foot = 0; // 重新设置foot属性的内容,作为索引出现 this.root.setNode(index, data); // 交给Node类设置数据内容 } /** * 链表数据的删除操作,在删除前要先使用contains()判断链表中是否存在指定数据 * 如果要删除的数据存在,则首先判断根节点的数据是否为要删除数据 * 如果是,则将根节点的下一个节点作为新的根节点 * 如果要删除的数据不是根节点数据,则将删除操作交由Node类的removeNode()方法完成 * @param data 要删除的数据 */ public void remove(Book data) { if (this.contains(data)) { // 主要功能是判断数据是否存在 // 要删除数据是否是根节点数据,root是Node类的对象,此处直接访问内部类的私有操作 if (data.equals(this.root.data)) { // 根节点数据为要删除数据 this.root = this.root.next; // 空出当前根节点 } else { // 根节点数据不是要删除数据 // 此时根元素已经判断过了,从第二个元素开始判断,即第二个元素的上一个元素为根节点 this.root.next.removeNode(this.root, data); } this.count--; // 删除成功后个数要减少 } } /** * 将链表中的数据转换为对象数组输出 * @return 如果链表没有数据返回null,如果有数据则将数据变为对象数组后返回 */ public Book[] toArray() { if (this.root == null) { // 判断链表是否有数据 return null; // 没有数据返回null } this.foot = 0; // 脚标清零操作 this.retArray = new Book[this.count]; // 根据保存内容开辟数组 this.root.toArrayNode(); // 交给Node类处理 return this.retArray; // 返回数组对象 } public void clear() { this.root = null; // 清空链表 this.count = 0; // 元素个数为0 } } |
范例1-135:实现测试。
public class LinkDemo { public static void main(String args[]) { Link all = new Link(); // 创建链表对象 all.add(new Book("Java开发实战经典",79.8)); // 保存数据 all.add(new Book("Oracle开发实战经典",89.8)); // 保存数据 all.add(new Book("Android开发实战经典",99.8)); // 保存数据 System.out.println("保存书的个数:" + all.size()) ; System.out.println(all.contains(new Book("Java开发实战经典",79.8))) ; all.remove(new Book("Android开发实战经典",99.8)) ; Book [] books = all.toArray() ; for (int x = 0 ; x < books.length ; x ++) { System.out.println(books[x].getInfo()) ; } } } |