【经典接口】
1. 经典接口③:java.lang.Cloneable
用于对象的克隆(复制)
在java.lang.Object根父类中有一个克隆对象的方法:
protected Object clone() throws CloneNotSupportedException
权限修饰符:protected(Object本类、java.lang本包、其他包的子类非静态方法中)
在子类(在克隆对象所在类中)中可以重写这个方法,修改protected为public
方法()后面有throws CloneNotSupportedException(不支持克隆异常),这个clone()方法很可能报异常
如果希望不报异常——让类实现java.lang.Cloneable接口
2. 经典接口④:java.lang.Iterable接口
实现这个接口允许对象称为“foreach”语句的目标
这个接口有一个抽象方法:Iterator iterator()
实现接口的抽象方法的快捷键是Ctrl+I
foreach是JDK1.5增加的语法,叫做增强for循环
JDK1.5之后,所有数组类型都默认实现这个接口,即支持foreach循环遍历数组
JDK1.5之后,很多集合也都支持
作用:遍历数组和集合容器元素
foreach语法:
for(元素的类型 元素临时名称:数组或集合容器对象名){
}
元素临时名称:局部变量名称,自己命名就可以,它就是临时代表一个元素
如,遍历元素就可以改为:
int[] arr = {1,2,3,4,5};
for(int num:arr){
System.out.println(num);
}
练习1:代码阅读分析结果
interface A{
int x = 0;
}
class B{
int x = 1;
}
class C extends B implements A{
public void pX(){
System.out.println(x);
}
public static void main(String[] args){
new C().pX();
}
}
结果:歧义,不通过
改为super.x或者A.x
练习2:代码分析
interface Playable{
void play();
}
interface Bounceable{
void play();
}
interface Rollable extends Playable,Bounceable{
Ball ball = new Ball("Pingpang")
}
class Ball implements Rollable{
private String name;
public String getName(){
return name;
}
public Ball(String name){
this.name = name;
}
public void play(){
ball = new Ball("Football");
System.out.println(ball.getName());
}
}
结果:错误
原因:ball是接口中的成员变量,是public static final,不能在play中重新命名
练习3:员工类和数组工具类、排序比较器
(1)声明一个Employee员工类
包含编号、姓名、薪资、年龄、属性私有化
提供get/set,提供无参和有参构造
重写toString,返回员工信息
实现Comparable接口,重写int compareTo(Object emp)方法,按照编号比较大小
(2)编写数组工具类ArrayTools,包含
静态方法public static void sort(Object[] arr):实现给对象数组从小到大排序,要求元素的运行时类型必须实现Comparable接口
静态方法public static void sort(Object[] arr,comparator c):实现给对象数组从小到大排序,需要提供一个Comparator接口的实现类对象,给数组的元素对象排序
静态方法public static void print(Object[] arr):使用foreach循环遍历输出数组元素
(3)在测试类创建Employee[]元素数组,长度为5,创建5个员工对象
按照编号从小到大排序输出
按照编号从大到小排序输出(声明一个类实现Comparator接口,实现按照编号逆序比较大小)
按照薪资从低到高排序输出(声明一个类实现Comparator接口,实现按照薪资比较大小)
按照年龄从大到小排序输出(声明一个类实现Comparator接口,实现按照年龄逆序比较大小)
代码:
Employee类:
public class Employee implements Comparable {
private int id;
private String name;
private double salary;
private int age;
public Employee() {
}
public Employee(int id, String name, double salary, int age) {
this.id = id;
this.name = name;
this.salary = salary;
this.age = age;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public int compareTo(Object o) {
return this.id - ((Employee)o).id;
}
@Override
public String toString() {
return "Employee{" +
"id=" + id +
", name='" + name + '\'' +
", salary=" + salary +
", age=" + age +
'}';
}
}
ArrayTools
import java.util.Comparator;
public class ArrayTools {
public static void sort(Object[] arr){
for (int i = 1; i < arr.length; i++) {
for (int j = 0; j < arr.length-i; j++) {
Comparable left = (Comparable)arr[j];
if(left.compareTo(arr[j+1])>0){
Object tmp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = tmp;
}
}
}
}
public static void sort(Object[] arr, Comparator c){
for (int i = 1; i < arr.length; i++) {
for (int j = 0; j < arr.length-i; j++) {
if(c.compare(arr[j],arr[j+1])>0){
Object tmp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = tmp;
}
}
}
}
public static void print(Object[] arr){
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
}
}
ID倒叙
import java.util.Comparator;
public class EmpIdReverseComparator implements Comparator {
@Override
public int compare(Object o1, Object o2) {
Employee e1 = (Employee)o1;
Employee e2 = (Employee)o2;
return e2.getId()-e1.getId();
}
}
薪资顺序
import java.util.Comparator;
public class EmpSalComparator implements Comparator {
@Override
public int compare(Object o1, Object o2) {
Employee e1 = (Employee)o1;
Employee e2 = (Employee)o2;
return Double.compare(e1.getSalary(),e2.getSalary());
}
}
年龄倒叙
import java.util.Comparator;
public class EmpAgeReverseComparator implements Comparator {
@Override
public int compare(Object o1, Object o2) {
Employee e1 = (Employee)o1;
Employee e2 = (Employee)o2;
return e2.getAge() - e1.getAge();
}
}
Test类
public class Test {
public static void main(String[] args) {
Employee[] e = new Employee[5];
e[0] =new Employee(1,"张三",15000,23);
e[1] =new Employee(3,"李四",12000,21);
e[2] =new Employee(4,"王五",14000,23);
e[3] =new Employee(5,"赵六",11000,24);
e[4] =new Employee(2,"陈琦",17000,27);
System.out.println("按id大小排序");
ArrayTools.sort(e);
ArrayTools.print(e);
System.out.println("按id大小逆序");
ArrayTools.sort(e,new EmpIdReverseComparator());
ArrayTools.print(e);
System.out.println("按照薪水排序");
ArrayTools.sort(e,new EmpSalComparator());
ArrayTools.print(e);
System.out.println("按照年龄逆序");
ArrayTools.sort(e,new EmpAgeReverseComparator());
ArrayTools.print(e);
}
}
【内部类知识点】
1. 什么是内部类
定义/声明在另一个类里面的类叫做内部类
2. 为什么要用内部类
总的原则:高内聚,低耦合
好处:
(1)可以突破权限修饰符的限制,内部类和外部类可以互相使用对方所有的(包括私有的)成员
(2)内部类通常情况下和外部类的关系非常紧密,内部类通常都是只为这个外部类服务的,不为其他类服务
(3)外部类的某些私有的成员不希望别的类了解或访问,只想给某个类使用,可以把这个类定义为外部类的内部类
3. 内部类的四种形式
(1)成员内部类(方法外)
静态内部类
非静态内部类
(2)局部内部类(方法体内)
有名字的局部内部类
匿名的内部类
4. 静态内部类
(1)语法格式
【修饰符】class 外部类{
【修饰符】static class 静态内部类{
}
}
(2)它是一个类
①它没有自己的字节码文件
有,字节码文字的命名:外部类$静态内部类名
即静态内部类的全名称:包.外部类名.静态内部类名
②可以有哪些修饰符
权限修饰符:public 、缺省
抽象修饰符:abstract
最终修饰符:final
③是否有自己的父类和父接口
可以有自己的父类和父接口,和外部类没有关系
④它可以有哪些成员
类的所有成员都有
(3)它是一个成员
①成员修饰符
权限修饰符:public、缺省、protected、private都可以
静态修饰符:static
最终修饰符:final
②在外部类的使用时,要依赖于外部类
③在外部类的里面使用,直接使用
(4)如何使用静态内部类?
①在外部类的外面
使用静态内部类的静态成员:外部类名.静态内部类名.静态成员
使用静态内部类的非静态成员:静态内部类对象.非静态成员
创建静态内部类的对象,外部类名.静态内部类名 变量= new 外部类名.静态内部类名()
②在外部类的里面
使用静态内部类的静态成员:静态内部类名.静态成员
使用静态内部类的非静态成员:静态内部类对象.非静态成员
创建静态内部类的对象,静态内部类名 变量= new 静态内部类名()
(5)在静态内部类中使用外部类成员
静态内部类不可以使用外部类的非静态成员
(6)当静态内部类中定义了和外部类重名的静态属性时怎么办
如果要访问外部类的静态成员,需要加“外部类名.”
5. 非静态内部类
(1)语法格式
【修饰符】class 外部类{
【修饰符】 class 非静态内部类{
}
}
(2)它是一个类
①它没有自己的字节码文件
有,字节码文字的命名:外部类$非静态内部类名
即非静态内部类的全名称:包.外部类名.非静态内部类名
②可以有哪些修饰符
权限修饰符:public 、缺省
抽象修饰符:abstract
最终修饰符:final
③是否有自己的父类和父接口
可以有自己的父类和父接口,和外部类没有关系
④它可以有哪些成员
非静态的内部类中,不允许有静态成员
(3)它是一个成员
①成员修饰符
权限修饰符:public、缺省、protected、private都可以
最终修饰符:final
②在外部类的使用时,要依赖于外部类,还要依赖于外部类的对象
③在外部类的里面使用,直接使用
(4)如何使用静态内部类?
①在外部类的外面
使用非静态内部类的非静态成员:非静态内部类对象.非静态成员
创建静态内部类的对象,外部类对象.new 非静态内部类()
②在外部类的里面
使用静态内部类的静态成员:静态内部类名.静态成员
使用静态内部类的非静态成员:静态内部类对象.非静态成员
创建静态内部类的对象,静态内部类名 变量= new 静态内部类名()
【注】在外部类的静态成员中,不允许使用非静态内部类
(5)在静态内部类中使用外部类成员
没有限制
(6)当静态内部类中定义了和外部类重名的静态属性时怎么办
如果要访问外部类的非静态成员,需要加“外部类名.this
6. 区别
静态内部类 | 非静态内部类 | ||
类角色 | 字节码文件 | 外部类名$内部类名 | 相同 |
修饰符 | public 缺省 abstract final | 相同 | |
父类或父接口 | 可以 | 相同 | |
可以包含的对象 | 所有成员 | 没有静态成员 | |
成员角色 | 修饰符 | public protected 缺省 private final static | 没有static |
依赖于外部类 | 依赖 | 相同 | |
依赖于外部类的对象 | 不依赖 | 依赖 | |
使用 | 在外部类中使用内部类 | 没有限制 | 在外部类的静态方法中不能使用非静态内部类 |
在内部类中使用外部类 | 静态内部类中不能使用外部类的非静态成员 | 没有限制 | |
在外部类的外面使用内部类的静态成员 | 外部类名.静态内部类名.静态成员 | 没有 | |
在外部类的外面使用内部类的非静态成员 | 外部类名.静态内部类 变量名= new 外部类名.静态内部类名(); 变量.非静态成员 | 外部类名 变量1 = new 外部类(); 外部类名.非静态内部类 变量名= 变量1.new 非静态内部类名(); 变量.非静态成员 | |
重名 | 外部类名.重名的成员 | 外部类名.this.重名成员 |
练习4:内部类代码阅读题
public class Test{
public Test(){
Inner s1 = new Inner();
s1.a = 10;
Inner s2 = new Inner();
s2.a = 20;
Test.Inner s3 = new Test.Inner();
System.out.println(s3.a);
}
class Inner{
public int a = 5;
}
public static void main(String[] args){
Test t = new Test();
Inner r = t.new Inner();
System.out.println(r.a);
}
}
结果:5
原因:实例变量是每一个对象“独立的”