11. JAVA常用类库 Part 4 (对象克隆技术clone、Arrays类、Comparable接口、比较器Comparator、观察者设计模式) ----- 学习笔记
来源:互联网 发布:和人工智能聊天的软件 编辑:程序博客网 时间:2024/04/30 05:57
在java中支持对象的克隆操作,直接使用Object类中的clone()方法即可。其方法定义如下:
protected Object clone() throws CloneNotSupportedException
上面的方法是受保护类型,所以在子类中必须覆写此方法,而且覆写后应该扩大该方法的访问权限,这样才能被外部调用,
但是具体的克隆方法的实现还是在Object中,所以在覆写的方法中只需要调用Object类中的clone()方法即可完成操作,而且在对象所在的类中必须实现Cloneable接口才可以完成对象的克隆操作。
JDK文档中,Cloneable接口中没有定义任何的方法,此接口在设计上称为一种标识接口,表示对象可以被克隆!!!!
范例:对象的克隆操作
/* * 对象克隆操作*/package org.forfan06.clonedemo;class Person implements Cloneable{ //必须实现Cloneable接口 private String name = null; public Person(String name){ this.name = name; } public String getName(){ return name; } public void setName(String name){ this.name = name; } public String toString(){ //覆写toString方法 return "姓名:" + this.getName(); } public Object clone() throws CloneNotSupportedException { return super.clone(); }}public class CloneDemo01{ public static void main(String args[]){ Person per1 = new Person("forfan06"); Person per2 = null; try { per2 = (Person) per1.clone(); //一定要进行异常的捕获处理 }catch(CloneNotSupportedException e){ e.printStackTrace(); } System.out.println("原对象:" + per1); System.out.println("克隆对象:" + per2); per2.setName("CSDN"); System.out.println("修改属性后的克隆对象:" + per2); }}
运行结果:
原对象:姓名:forfan06克隆对象:姓名:forfan06修改属性后的克隆对象:姓名:CSDN
11.12 Arrays类
Arrays类是数组的操作类,定义在java.util包中,主要功能是实现数组元素的查找、数组内容的填充、排序等等。其常用方法如下:
<span style="font-size:12px;">public static boolean equals(int[] a, int[] a2) //判断两个数组是否相等,此方法被重载多次,可以判断各种数据类型的数组</span>
<span style="font-size:12px;">public static void fill(int[] a, int val) //将指定内容填充到数组之中,此方法被重载多次,可以填充各种数据类型的数组</span>
<span style="font-size:12px;">public static void sort(int[] a) //数组排序,此方法被重载多次,可以对各种类型的数组进行排序</span>
<span style="font-size:12px;">public static int binarySearch(int[] a, int key) //对排序后的数组进行检索,此方法被重载多次,可以对各种类型的数组进行搜索</span>
<span style="font-size:12px;">public static String toString(int[] a) //此方法被重载多次,可以输出各种数据类型的数组</span>
范例:操作Arrays类
/* * 操作Arrays类*/package org.forfan06.arraydemo;import java.util.Arrays;public class ArrayDemo01{ public static void main(String args[]){ int temp[] = {3, 5, 9, 7, 1, 15, 27, 38, 4, 2, 98}; System.out.println("原始数组:"); System.out.println(Arrays.toString(temp)); Arrays.sort(temp); System.out.println("排序后的数组:"); System.out.println(Arrays.toString(temp)); int point1 = Arrays.binarySearch(temp, 4); System.out.println("元素‘4’的位置在:" + point1); int point2 = Arrays.binarySearch(temp, 0); System.out.println("元素‘4’的位置在:" + point2); Arrays.fill(temp, 4, 5, 77); System.out.println("数组填充:"); System.out.println(Arrays.toString(temp)); }}
运行结果:
原始数组:[3, 5, 9, 7, 1, 15, 27, 38, 4, 2, 98]排序后的数组:[1, 2, 3, 4, 5, 7, 9, 15, 27, 38, 98]元素‘4’的位置在:3元素‘4’的位置在:-1数组填充:[1, 2, 3, 4, 77, 7, 9, 15, 27, 38, 98]
11.13 Comparable接口
11.13.1 比较器的基本应用
使用java.util.Arrays类进行数组的排序操作时,Arrays类中的sort()方法被重载多次,可以对任意类型的数组排序,排列时会根据数值的大小进行排序。同样此类也可以对Object数组进行排序,但是要使用此种方法排序需要对象所在的类必须实现Comparable接口,此接口就是用于指定对象排序规则的。
Comparable接口的定义如下:
public interface Comparable<T>{ public int compareTo(T o);}
在Comparable接口中使用了Java的泛型技术。该接口中只有一个compareTo方法,此方法返回一个int类型的数据。其返回值int 的值只能是以下3种:
- 1: 表示大于
- -1: 表示小于
- 0: 表示等于
范例:设计一个学生类,该类包含姓名、年龄、成绩 ,并产生一个对象数组,要求按照成绩由高到低排序,如果成绩相等,则按年龄由低到高排序。 使用Arrays类中的sort()方法进行排序操作。
package org.forfan06.comparabledemo;<span style="color:#ff0000;"><strong>class Student implements Comparable<Student></strong></span>{ //指定泛型类型为Student类型 private String name; private int age; private float score; public Student(String name, int age, float score){ this.setName(name); this.setAge(age); this.setScore(score); } public void setName(String name){ this.name = name; } public void setAge(int age){ this.age = age; } public void setScore(float score){ this.score = score; } public String getName(){ return name; } public int getAge(){ return age; } public float getScore(){ return score; } public String toString(){ return this.getName() + "\t\t" + this.getAge() + "\t\t" + this.getScore(); } public int compareTo(Student stu){ //覆写compareTo()方法,实现排序规则应用 if(this.getScore() > stu.getScore()){ return -1; }else if(this.getScore() < stu.getScore()){ return 1; }else{ if(this.getAge() > stu.getAge()){ return 1; }else if(this.getAge() < stu.getAge()){ return -1; }else{ return 0; } } }}public class ComparableDemo01{ public static void main(String args[]){ Student stu[] = {new Student("forfan06", 27, 75.8f), new Student("dylan", 15, 13.2f), new Student("csdn", 35, 13.2f)}; java.util.Arrays.sort(stu); //调用排序方法进行排序 for (int i = 0; i < stu.length; i++){ //输出 System.out.println(stu[i]); } }}
运行结果:
forfan062775.8dylan1513.2csdn3513.2
如果此时Student类没有实现Comparable接口,则会发生运行时异常!!!!!!!!此异常是类型转换异常,因为在排序时,所有的对象都将向Comparable类型进行转换,所以,一旦没有实现该接口就会出现以下错误
Exception in thread "main" java.lang.ClassCastException: Student cannot be cast to java.lang.Comparableat java.util.ComparableTimSort.countRunAndMakeAscending(ComparableTimSort.java:290)at java.util.ComparableTimSort.sort(ComparableTimSort.java:157)at java.util.ComparableTimSort.sort(ComparableTimSort.java:146)at java.util.Arrays.sort(Arrays.java:472)at ComparableDemo01.main(Unknown Source)执行错误
11.13.2 分析比较器的排序原理
实际上,上面的程序ComparableDemo01的排序过程就是数据结构中的二叉树排序方法,通过二叉树进行排序,然后利用中序遍历的方式把内容一次读取出来。
二叉树排序的基本原理就是:将第1个内容作为根节点保存,如果后面的值比根节点的值小,则放在根节点的左子树;如果后面的值比根节点的值大,则放在根节点的右子树。
按照这样的思路,如果给出了数字8、 3、 10、 9、 1、 5,则保存的树结构如下图所示:
然后根据中序遍历的原理(左子树 --> 根节点 --> 右子树的方式)即可将数字排序读取出来,排序后的结果为1、 3、 5、 8、 9、 10。
按照上面的思路编写一个简单的二叉树排序操作。(为了简化代码,直接使用Integer类,因为Integer类本身就已经实现了Comparable接口)
(1)范例:Integer为Comparable接口实例化
/* * Integer为Comparable接口实例化*/package org.forfan06.comparabledemo;public class ComparableDemo02{ public static void main(String args[]){ Comparable comp = null; //声明一个Comparable接口对象 comp = 30; //通过Integerl类为Comparable接口实例化 System.out.println("内容是:" + comp); //实际上调用的是toString()方法 }}
运行结果:
内容是:30
(2)范例:基于Comparable接口实现的二叉树操作
package org.forfan06.comparabledemo;class BinaryTree{ class Node{ //声明一个节点类 private Comparable data; //保存具体内容 private Node left; //保存左、右子树 private Node right; public void addNode(Node newNode){ //要确定是放在左子树,还是右子树。比当前节点小的放在左子树;比当前节点大或相等的放在右子树 if (newNode.data.compareTo(this.data) < 0){ if(this.left == null){ //放在左子树 this.left = newNode; }else{ this.left.addNode(newNode); } } if (newNode.data.compareTo(this.data) >= 0){ if(this.right == null){ //放在右子树 this.right = newNode; }else{ this.right.addNode(newNode); } } } public void printNode(){ //输出采用中序遍历 if(this.left != null){ //先输出左子树 this.left.printNode(); } System.out.print(this.data + "\t"); //再输出根节点 if(this.right != null){ //最后输出右子树 this.right.printNode(); } } } private Node root; //根元素 public void add(Comparable data){ Node newNode = new Node(); //每传入一个新的内容就声明一个根节点 newNode.data = data; if (root == null){ root = newNode; }else{ root.addNode(newNode); } } public void print(){ this.root.printNode(); }}public class ComparableDemo03{ public static void main(String args[]){ BinaryTree bt = new BinaryTree(); bt.add(8); bt.add(3); bt.add(3); bt.add(10); bt.add(9); bt.add(1); bt.add(5); bt.add(5); System.out.println(""); bt.print(); }}
运行结果:
ComparableDemo03.java uses unchecked or unsafe operations.Note: Recompile with -Xlint:unchecked for details.133558910上面程序的实现实际上与链表操作类似,只是多增加了一个节点的引用操作。Java中对各个常见的数据结构算法提供了很好的支持,详细操作在Java类集部分讲解!!!
PS: 尝试修改上面的程序,来实现二叉树的另外两种遍历方式!!!!!
11.14 另一种比较器Comparator
如果一个类已经开发完成,但是在此类建立的初期并没有实现Comparable接口,此时肯定是无法进行对象排序操作的。此时就可以考虑到用java中的另一个比较器的操作接口 ---->>>Comparator
Comparator接口定义在java.util包中,定义格式如下:
public interface Comparator<T>{ public int compare(T o1, T o2); //Compares its two arguments for order boolean equals(Object obj); // Indicates whether some other object is "equal to" this comparator}
- Comparable<T> interface in java.lang
- Comparator<T> interface in java.util
在Comparator接口中也有一个比较方法compare(T o1, T o2), 此方法要接收2个对象, 其返回值依然是0、 -1、 1
Comparator接口需要单独指定好一个比较器的比较规则类才可以完成数组排序。下面定义一个学生类,其中有姓名、年龄属性,并按照年龄排序
范例:(1)定义学生类
package org.forfan06.comparatordemo;public class Student{ private String name; private int age; public Student(String name, int age){ this.setName(name); this.setAge(age); } public void setName(String name){ this.name = name; } public String getName(){ return this.name; } public void setAge(int age){ this.age = age; } public int getAge(){ return this.age; } //@override equals() method public boolean equals(Object obj){ if (this == obj){ return true; } if(!(obj instanceof Student)){ return false; } Student stu = (Student) obj; if(stu.name.equals(this.name) && stu.age == this.age){ return true; }else{ return false; } } //@override toString() public String toString(){ return this.getName() + "\t\t" + this.getAge(); }}
(2)定义比较规则
//package org.forfan06.comparatordemo;import java.util.Comparator;public class StudentComparator implements Comparator<Student>{ //指定泛型类型为Student public int compare(Student s1, Student s2){ if(s1.equals(s2)){ return 0; }else if(s1.getAge() < s2.getAge()){ return 1; //倒序排列 }else{ return -1; } }}
(3)为对象数组排序
<pre class="java" name="code"><pre class="java" name="code">package org.forfan06.comparatordemo;public class ComparatorDemo{ public static void main(String args[]){ Student stu[] = {new Student("forfan06", 27), new Student("csdn", 21), new Student("dylan", 7), new Student("zhuzhu", 2), new Student("maomao", 3), new Student("gougou", 2), new Student("Sam", 21)}; java.util.Arrays.sort(stu, new StudentComparator()); //排序,指定排序的规则 for(int i = 0; i < stu.length; i++){ System.out.println(stu[i]); } }}
运行结果:
forfan0627Sam21csdn21dylan7maomao3gougou2zhuzhu2
- Comparator接口和Comparable接口都可以实现相同的排序功能,但是与Comparable接口相比,Comparator接口只是一种补救的措施。建议还是使用Comparable接口进行排序比较方便!!
11.15 观察者设计模式
11.15.1 什么叫观察者
观察者设计模式: 现在有很多的购房者都在关注着房子的价格变化,每当房子价格变化时,所有的购房者都可以观察到; 实际上以上的购房者都属于观察者,他们都在关注着房子的价格。 这就叫观察者设计模式!!如下图所示:
在java中可以直接依靠Observable类和Observer接口轻松地实现以上功能。
11.15.2 观察者模式实现
在java.util包中提供了Observable类和Observer接口,使用它们即可完成观察者模式。
(1)需要被观察的类必须继承Observable类,Observable类的常用方法如下所示:
public void addObserver(Observer o) //添加一个观察者
public void deleteObserver(Observer o) //删除一个观察者
protected void setChanged() //被观察者状态发生改变
public void notifyObservers(Object arg) //通知所有观察者状态改变
(2)然后每一个观察者类都需要实现Observer接口。Observer接口定义如下:
public interface Observer{ void update(Observable o, Object arg);}
该接口中只定义了一个update方法,第1个参数表示被观察者实例,第2个参数表示修改的内容
范例:观察着模式的实现
package org.forfan06.observerdemo;import java.util.Observable;import java.util.Observer;class House extends Observable{ private float price; public House(float price){ this.price = price; } public float getPrice(){ return price; } public void setPrice(float price){ super.setChanged(); //设置变化点 super.notifyObservers(price); //通知所有观察者价格变化 this.price = price; } public String toString(){ return "房子价格:" + this.price; }}class HousePriceObserver implements Observer{ private String name; public HousePriceObserver(String name){ this.name = name; } public void update(Observable obj, Object arg){ if(arg instanceof Float){ //判断参数类型 System.out.print(this.name + "观察到价格更改为:"); System.out.println(((Float) arg).floatValue()); } }}public class ObserverDemo01{ public static void main(String args[]){ House h = new House(1000000); HousePriceObserver hpo1 = new HousePriceObserver("AAA"); HousePriceObserver hpo2 = new HousePriceObserver("BBB"); HousePriceObserver hpo3 = new HousePriceObserver("CCC"); h.addObserver(hpo1); h.addObserver(hpo2); h.addObserver(hpo3); System.out.println(h); //输出房子价格 h.setPrice(666666); System.out.println(h); }}
运行结果:
房子价格:1000000.0CCC观察到价格更改为:666666.0BBB观察到价格更改为:666666.0AAA观察到价格更改为:666666.0房子价格:666666.0
- 11. JAVA常用类库 Part 4 (对象克隆技术clone、Arrays类、Comparable接口、比较器Comparator、观察者设计模式) ----- 学习笔记
- Java常用类库--Arrays、比较器(comparable、Comparator)
- Java常用类库--对象克隆技术clone
- java常用类库续3(比较器Comparable、Comparator、观察者设计模式、正则表达式、定时调度)
- Java常用类库——Arrays类(用于普通数组操作)、比较器(Comparable、Comparator 用于对象排序)的使用
- JAVA常用类库---比较器(Comparable、Comparator)
- java常用类库---比较器(Comparable,Comparator)
- 【Java常用类库】_比较器(Comparable、Comparator)笔记
- 【Java常用类库】_比较器(Comparable、Comparator)笔记
- 【Java常用类库】_对象克隆技术笔记
- 【Java常用类库】_对象克隆技术笔记
- java常用类库---对象克隆技术
- Java 用Arrays.sort()对对象数组排序之comparable接口和comparator比较器
- java学习笔记13--比较器(Comparable、Comparator)
- java常用类库续2(大数操作BigInteger、BigDecimal类、对象克隆技术、Arrays类)
- java比较器comparable接口和comparator接口
- Java Comparable排序接口和Comparator比较器接口
- java Comparable接口与Comparator接口比较
- 手机意外删除系统文件该怎么恢复呢
- 可以用jQuery代替$避免冲突
- Cocos2d-x开发实例介绍帧动画使用
- C/C++编程技巧总结
- 如何调试移动端页面
- 11. JAVA常用类库 Part 4 (对象克隆技术clone、Arrays类、Comparable接口、比较器Comparator、观察者设计模式) ----- 学习笔记
- Android中内容观察者的使用---- ContentObserver类详解
- framework.functions
- 数组的快速排序(递归,需要隐性栈空间)
- 使用ExtJs 来显示数据,并实现数据的分页功能
- 【POJ】1523 SPF 割点
- iOS 程勋奔溃-一种调试方法 lidb命令
- kmalloc、vmalloc、malloc的区别
- 贪心小结