Java 笔记 13
接口
接口的思想,一开始不好理解。但是语法很简单。
*
- 1、接口
- 行为标准
- 生活中:
- 例如:USB接口
- 有了标准,
- (1)电脑设计时简单了,多提供几个USB接口,就可以让很多的设备和我电脑连接
- (2)对于其他设备的厂商也简单了,只要你这个设备有与电脑连接的需求,那么就可以把连接口设计为USB
- 例如:电源接口
- 有了标准:
- (1)插座的设计
- (2)电器的设计
- Java中:
- 为了限定某些类(这些类之间可能没有继承关系,甚至都不是一个派系里面的),但是这些类都具有相同的行为特征。
- 例如:
- Bird类
- Plane类
- Kite类
- 这些类不是同一个父类派生出来的,但是又希望它们有相同的行为特征,这个时候就可以设计接口。
- 这个时候通过这个接口就可以同时管理这些类。
- 例如:JDBC
- Java中,设计了很多接口,Connection(连接数据库),Statement(执行sql语句),ResultSet(返回结果)
- Java中无法去替数据库厂商,去编写代码,那只能设计标准。
- 因为数据库厂商太多了,有oracle,mysql,sql server,db2…
- 如果你的数据库厂商的数据库产品想要和我Java程序连接,那么就必须遵循我的标准。
- 2、如何声明接口?
- 3、使用者如何去实现接口?
一、如何声明接口?
- 1、接口的语法格式:
- 【权限修饰符】 interface 接口名{
-
接口的成员列表;
- }
- 2、接口的成员
- JDK1.8之前:只能有两种成员
- (1)全局的静态的常量:public static final,而且这三个单词可以省略
- 为什么只能是常量?
- 因为标准中,只能写定死的
- (2)公共的抽象的方法:public abstract,而且这两个单词可以省略
- 为什么只能是抽象方法?
- 标准中只规定有什么行为标准,行为特征。至于你怎么实现,那么你自己说了算。
- 二、 如何实现接口?
- 语法格式:
- 【修饰符】 class 实现类 implements 父接口们{
- }
- 三、接口的特点
- 1、接口是标准,就是用来被遵守的,即就是用来被实现的,那么要求实现类在实现接口时,必须实现/重写所有的抽象方法,
- 否则这个实现类就得是一个抽象类。
- 2、接口也是不能直接创建对象的
- 3、接口类型的变量与实现类的对象构成多态引用
- 4、一个类继承父类时,我们说Java只支持单继承,但是一个类在实现接口时,可以同时实现多个接口
- 5、一个类如果同时继承父类,又实现接口时,要求继承在前,实现在后
- 【修饰符】 class 实现类 extends 父类 implements 父接口们{
- }
- 6、在Java中,接口还可以继承接口
- 【权限修饰符】 interface 子接口 extends 父接口们{
- }
public class TestInterfaceDefineAndUse {
public static void main(String[] args) {
// Flyable f = new Flyable();//接口不能直接创建对象的
Flyable[] sky = new Flyable[3];
//数组的元素类型Flyable类型,是接口类型
sky[0] = new Bird();//多态引用
sky[1] = new Plane();
sky[2] = new Kite();
for (int i = 0; i < sky.length; i++) {
//数组的元素类型Flyable类型,是接口类型
sky[i].fly();
}
}
}
//声明一个Flyable接口
interface Flyable{
// public static final long MAX_SPEED = 7900000;
long MAX_SPEED = 7900000;
// public abstract void fly();
void fly();
}
//声明一个Jumpable接口
interface Jumpable{
void jump();
}
class Animal{
}
//让小鸟继承Animal,并实现Flyable和Jumpable
class Bird extends Animal implements Flyable,Jumpable {
//重写接口的抽象方法,实现接口的抽象方法
@Override
public void fly() {
System.out.println("小鸟振翅高飞");
}
@Override
public void jump() {
System.out.println("双脚跳");
}
}
class Plane implements Flyable{
@Override
public void fly() {
System.out.println("靠发动机带动飞行");
}
}
class Kite implements Flyable{
@Override
public void fly() {
System.out.println("靠人放");
}
}
interface A{
void a();
}
interface B{
void b();
}
interface C extends A,B{
void c();
}
class Impl implements C{
@Override
public void a() {
}
@Override
public void b() {
}
@Override
public void c() {
}
}
java.util.Comparator
java.util.Comparator接口:
- 抽象方法:int compare(T o1, T o2)
- 因为是泛型,我们还没讲。现在就把T擦除,换成Object
- java.util.Comparator接口:
-
抽象方法:int compare(Object o1, Object o2)
- 这个接口是代表Java中比较两个对象的大小标准。而且是一种“定制”比较的标准。
- 这个接口中没有规定如何比较两个对象的大小,
- 但是规定了,如果你认为o1 大于 o2,就返回正整数表示
-
如果你认为o1 小于 o2,就返回负整数表示
-
如果你认为o1 等于 o2,就返回0表示
public class TestComparator {
public static void main(String[] args) {
Student s1 = new Student("杨洪强", 24, 89);
Student s2 = new Student("苏海波", 23, 100);
//比较s1和s2的大小
/*if(s1 > s2){//错误的
System.out.println("s1 > s2");
}*/
AgeComparator c = new AgeComparator();
if(c.compare(s1, s2) > 0){//如果比较s1,s2的结果是正整数,说明s1>s2
System.out.println("s1 > s2的年龄");
}else if(c.compare(s1, s2) <0){
System.out.println("s1 < s2的年龄");
}else{
System.out.println("s1 = s2的年龄");
}
ScoreComparator s = new ScoreComparator();
if(s.compare(s1, s2) > 0){//如果比较s1,s2的结果是正整数,说明s1>s2
System.out.println("s1 > s2的成绩");
}else if(s.compare(s1, s2) <0){
System.out.println("s1 < s2的成绩");
}else{
System.out.println("s1 = s2的成绩");
}
System.out.println("-------------------------------------");
Student[] all = new Student[5];
all[0] = s1;
all[1] = s2;
all[2] = new Student("张三",23,88);
all[3] = new Student("李四",24,44);
all[4] = new Student("王五",25,45);
//Arrays工具类
// Arrays.sort(all);
/*
* public static void sort(Object[] a, Comparator c)
* 第一个形参:需要排序的数组,Object[]说明可以是任意类型的对象数组
* 第二个形参:比较器对象 Comparator接口不能创建对象,只能传入实现类对象
*/
// Arrays.sort(all, new AgeComparator());
//按照成绩必须交
Arrays.sort(all, new ScoreComparator());
for (int i = 0; i < all.length; i++) {
System.out.println(all[i]);
}
}
}
//实现Comparator接口,来定制两个学生比较的具体实现方式
//例如:按照年龄比较
class AgeComparator implements Comparator{
@Override
public int compare(Object o1, Object o2) {
//(1)向下转型
Student s1 = (Student) o1;
Student s2 = (Student) o2;
//(2)开始比较
if(s1.getAge() > s2.getAge()){
return 1;
}else if(s1.getAge() < s2.getAge()){
return -1;
}
return 0;
}
}
//实现Comparator接口,来定制两个学生比较的具体实现方式
//例如:按照成绩比较
class ScoreComparator implements Comparator{
@Override
public int compare(Object o1, Object o2) {
//(1)向下转型
Student s1 = (Student) o1;
Student s2 = (Student) o2;
//(2)开始比较
if(s1.getScore() > s2.getScore()){
return 1;
}else if(s1.getScore() < s2.getScore()){
return -1;
}
return 0;
}
}
class Student{
private String name;
private int age;
private int score;
public Student(String name, int age, int score) {
super();
this.name = name;
this.age = age;
this.score = score;
}
public Student() {
super();
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public int getScore() {
return score;
}
public void setScore(int score) {
this.score = score;
}
@Override
public String toString() {
return "Student [name=" + name + ", age=" + age + ", score=" + score + "]";
}
}
java.lang.Comparable
java.util.Comparator:定制比较,定制顺序
-
int compare(Object o1, Object o2):
-
o1与o2比较,o1>o2,返回正整数
-
o1与o2比较,o1<o2,返回负整数
-
o1与o2比较,o1=o2,返回0
- java.lang.Comparable:自然比较,自然顺序
-
int compareTo(Object obj)
-
this与obj对象比较,this > obj,返回正整数
-
this与obj对象比较,this < obj,返回负整数
-
this与obj对象比较,this = obj,返回0
- 上午讲的定制比较器,用定制比较器的对象,比较两个学生对象:
-
AgeComparator c = new AgeComparator();
-
if(c.compare(s1, s2) > 0){...}
- 希望学生对象本身就具备比较大小的能力。
public class TestComparable {
public static void main(String[] args) {
Student s1 = new Student("杨洪强", 24, 89);
Student s2 = new Student("苏海波", 23, 100);
//按成绩比较
if(s1.compareTo(s2)>0){
System.out.println("s1 > s2成绩");
}else if(s1.compareTo(s2)<0){
System.out.println("s1 < s2成绩");
}else{
System.out.println("s1 = s2成绩");
}
//按年龄比较,只能再用定制比较,补充完成这个功能
}
}
class Student implements Comparable{
private String name;
private int age;
private int score;
public Student(String name, int age, int score) {
super();
this.name = name;
this.age = age;
this.score = score;
}
public Student() {
super();
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public int getScore() {
return score;
}
public void setScore(int score) {
this.score = score;
}
@Override
public String toString() {
return "Student [name=" + name + ", age=" + age + ", score=" + score + "]";
}
@Override
public int compareTo(Object obj) {
//this与obj比较,this和obj都是学生对象
Student other = (Student) obj;
//例如:对于学生对象来说,最常用的是按成绩排名,那么我就可以把自然顺序定位成绩升序
/* if(this.score > other.score){
return 1;
}else if(this.score < other.score){
return -1;
}
return 0;*/
return this.score - other.score;
}
}
总结:
- Arrays的sort方法有两种:
- (1)void sort(Object[] arr):
-
根据元素的自然顺序对指定对象数组按升序进行排序。数组中的所有元素都必须实现 Comparable 接口。
- (2)void sort(Object[] arr, Comparator c):
-
根据“指定比较器”产生的顺序对指定对象数组进行排序。数组中的所有元素都必须是通过“指定比较器”可相互比较的
public class TestArrays {
public static void main(String[] args) {
Student[] all = new Student[5];
all[0] = new Student("杨洪强", 24, 89);
all[1] = new Student("苏海波", 23, 100);
all[2] = new Student("张三",23,88);
all[3] = new Student("李四",24,44);
all[4] = new Student("王五",25,45);
//如果我们的学生类Student,实现了java.lang.Comparable接口,
//能不能按照自然排序的规则进行排序呢
//Arrays中有这样的方法
//public static void sort(Object[] a)
Arrays.sort(all);//这里面排序过程中,调用了元素本身的compareTo()方法
//因为元素本身是Student类型,它实现了java.lang.Comparable接口
//本身就具备比较大小的能力,即拥有compareTo()方法
for (int i = 0; i < all.length; i++) {
System.out.println(all[i]);
}
}
}
练习
Employee.java
package com.java.test1;
public class Employee implements Comparable<Object>{
private int num;
private String name;
private int age;
private int salary;
public Employee(int num, String name, int age, int salary) {
super();
this.num=num;
this.age=age;
this.name=name;
this.salary=salary;
}
public Employee() {
super();
}
public int getNum() {
return this.num;
}
public int getSalary() {
return this.salary;
}
@Override
public int compareTo(Object o) {
// TODO Auto-generated method stub
Employee e = (Employee)o;
if(this.num>e.getNum()) {
return 1;
}else if(this.num<e.getNum()) {
return -1;
}
return 0;
}
@Override
public String toString() {
return "Employee [id=" + num + ", name=" + name + ", age=" + age + ", salary=" + salary + "]";
}
}
SalaryComparator.java
package com.java.test1;
import java.util.Comparator;
public class SalaryComparator implements Comparator<Object> {
@Override
public int compare(Object o1, Object o2) {
// TODO Auto-generated method stub
Employee e1 = (Employee)o1;
Employee e2 = (Employee)o2;
if(e1.getSalary()>e2.getSalary()) {
return 1;
}else if(e1.getSalary()<e2.getSalary()) {
return -1;
}
return 0;
}
}
test.java
package com.java.test1;
import java.util.Arrays;
public class test {
public static void main(String[] args) {
Employee[] all = new Employee[3];
all[0] = new Employee(2, "王小二", 22, 20000);
all[1] = new Employee(3, "张三", 23, 13000);
all[2] = new Employee(1, "李四", 24, 8000);
//调用java.util.Arrays的sort方法进行排序,遍历结果
Arrays.sort(all);
for (int i = 0; i < all.length; i++) {
System.out.println(all[i]);
}
System.out.println("-----------------------------");
//再次调用java.util.Arrays的sort方法进行排序,遍历结果
Arrays.sort(all, new SalaryComparator());
for (int i = 0; i < all.length; i++) {
System.out.println(all[i]);
}
}
}
Java中对象要比较大小,:(1)实现Comparable(2)实现Comparator
*
- 我们发现:java.lang.String类型,实现了Comparable接口,
- 说明String类型中有int compareTo(Object obj)
public class TestString {
public static void main(String[] args) {
String s1 = "Hello";
String s2 = "hai";
/* if(s1 > s2){//因为String类型是引用数据类型,是无法直接用>和<等比较运算符比较大小的
//...
}*/
/*
* h和c比较,h>c,直接就决定了s1>s2
*/
if(s1.compareTo(s2)>0){
System.out.println("s1 > s2");
}else if(s1.compareTo(s2)<0){
System.out.println("s1 < s2");
}else{
System.out.println("s1 = s2");
}
Employee[] all = new Employee[3];
all[0] = new Employee("2", "王小二", 22, 20000);
all[1] = new Employee("3", "张三", 23, 13000);
all[2] = new Employee("1", "李四", 24, 8000);
Arrays.sort(all);
for (int i = 0; i < all.length; i++) {
System.out.println(all[i]);
}
}
}
JDK1.8 接口新特性
1、Java8对接口进行了修改:
- Java8之前,接口中的成员只有两种:
- (1)全局的静态的常量:public static final,可以省略
- (2)公共的抽象的方法:public abstract,可以省略
- Java8之后,接口又增加了两种新成员:
- (3)静态方法:public static,不可以省略
-
调用方式:接口名.静态方法(实参列表)
- (4)默认方法:public default,不可以省略
- 2、为什么Java8要允许接口中定义静态方法?
- 是因为JDK发展了一段时间后,发现类库中,多了很多这样的成组的API:
- (1)Path接口和Paths工具类
- (2)Collection接口和Collections工具类
- …
- 一般工具类中都是静态方法,这些静态方法,基本上都是为前面这个对应接口服务的。
- 这样的话,就会出现很多API,使得程序员的学习成本增加了,使用成本也增加了。
- 开始把这样的静态方法,直接挪到接口中定义就好了。减少了这样的工具类的出现。
- 3、为什么么Java8要允许接口中定义默认方法?
- 是因为有的时候,一个接口它的大多数实现类对接口的抽象方法的实现代码是一样,那么我们写好几次就太麻烦了。
- 即相当于,默认方法是原来的抽象方法有了一个默认实现。如果实现类的实现和接口一样,就不需要重写,如果不一样就重写即可。
- 4、冲突问题
- (1)当一个类同时实现了两个甚至更多个接口时,这些个接口中出现了方法签名相同的默认方法时,
- 那么我们必须在这个实现类中,做出选择。
- 选择一:保留其中一个,放弃另一个
- 选择二:两者都不用,完全重写一个
- (2)当一个类同时继承了父类,又实现了接口,那么当父类中出现了和接口中方法签名一样的方法时,怎么办?
- 那么我们怎么选择?
- 选择一:默认选择,编译器默认选择父类
- 选择二:改选保留接口的
- 选择三:完全自己重写
public class TestInterface18 {
public static void main(String[] args) {
MyInter.test();
// MyInter my = new MyInter();//接口不能创建对象
// MyInter my = new InterImpl1();
// my.method();
Son s = new Son();
s.test();
}
}
interface MyInter{
public static void test(){
System.out.println("接口中的静态方法");
}
void fun();
public default void method(){
System.out.println("接口中的默认方法");
}
}
class InterImpl1 implements MyInter{
@Override
public void fun() {
System.out.println("aaaa");
}
}
class InterImpl2 implements MyInter{
@Override
public void fun() {
System.out.println("aaaa");
}
}
class InterImpl3 implements MyInter{
@Override
public void fun() {
System.out.println("bbbb");
}
//在类中,重写接口的默认方法是,default要去掉
@Override
public void method() {
System.out.println("重写接口的默认方法");
}
}
interface A{
public default void test(){
System.out.println("aaa");
}
}
interface B{
public default void test(){
System.out.println("bbb");
}
}
class C implements A,B{
//选择一:保留其中一个,放弃另一个
//在类中,重写接口的默认方法是,default要去掉
/* public void test(){
// A.super.test();//保留A接口的实现
B.super.test();//保留B接口的实现
}*/
public void test(){
System.out.println("ccc");
}
}
class Father{
public void test(){
System.out.println("ffff");
}
}
interface D{
public default void test(){
System.out.println("dddd");
}
}
class Son extends Father implements D{
//选择一:默认选择,保留父类的
//选择二:该选,保留干爹的
// public void test(){
// D.super.test();
// }
//选择三:完全自己重写
public void test(){
System.out.println("ssss");
}
}
内部类
1、内部类:
- 定义在另外一个类里面的类,就叫做内部类,为了区别,把外面的类称为外部类。
- 2、分类
- 根据内部类的所在的位置不同:
- (1)成员内部类:外部类中方法外
- (2)局部内部类:方法体内,(虽然也可以在代码块内,但是不讨论这个)
- 成员内部类:
- (1)有static修饰的:静态成员内部类,我们通常就简称为静态内部类
- (2)没有static修饰的:非静态成员内部类,我们通常就简称为成员内部类
- 【修饰符】 class 外部类{
-
【其他修饰符】 static class 静态内部类{
-
}
-
【其他修饰符】 class 非静态成员内部类{
-
}
- }
- 【修饰符】 class 外部类 【extends 父类】 【implements 父接口们】{
-
【其他修饰符】 static class 静态内部类 【extends 父类】 【implements 父接口们】{
-
}
-
【其他修饰符】 class 非静态成员内部类 【extends 父类】 【implements 父接口们】{
-
}
- }
- 说明:外部类、内部类的父类、父接口没有关系,各是各的
- 局部内部类:
- (1)有名字的局部内部类:简称局部内部类
- (2)没名字的局部内部类:简称匿名内部类
- 局部内部类的语法格式:
- 【修饰符】 class 外部类 【extends 父类】 【implements 父接口们】{
-
【修饰符】 返回值类型 方法名(【形参列表】){
-
【修饰符】 class 有名字的局部内部类 【extends 父类】 【implements 父接口们】{
-
...
-
}
-
}
- }
匿名内部类
- 匿名内部类的语法格式:
- 特殊
一、匿名内部类 - 语法格式:
- new 父类名(【实参列表】){
-
类的成员列表
- }
- 说明:如果你子类调用的是父类的无参构造,那么()中实参列表不用写,如果子类调用的是父类的有参构造,那么就在()中传入实参列表
- 或
- new 父接口名(){
- 类的成员列表
- }
- 特殊:声明匿名内部类与创建它的对象是一起完成的。即匿名内部类只有唯一的对象。
public class TestAnonymousInner {
@SuppressWarnings("unchecked")
public static void main(String[] args) {
//1、需求1:要声明一个Object的子类,匿名子类,
//并在子类中声明一个方法public void test(){}打印“hello匿名内部类"
//下面这段代码,声明了匿名内部类,也创建了它的对象
//但是没有说这个对象干什么,编译不通过的。
/* new Object(){
public void test(){
System.out.println("hello匿名内部类");
}
}*/
//(1)我们可以把这个对象,赋值给一个变量
//多态引用
Object obj1 = new Object(){
public void test(){
System.out.println("hello匿名内部类");
}
};
System.out.println(obj1.getClass());//获取对象的运行时类型
System.out.println(obj1);//打印对象时,自动对象的toString()
//这是另一个Object的匿名子类的对象
/* Object obj2 = new Object(){
public void test(){
System.out.println("hello匿名内部类");
}
};*/
// (2)我们可以用这个对象,直接调用方法
//匿名内部类的匿名对象.方法()
new Object(){
public void test(){
System.out.println("hello匿名内部类");
}
}.test();
//java.util.Comparator接口
//我要在这里声明一个比较器类型,用于比较两个圆的半径大小
//把一个Comparator接口的匿名实现类对象,赋值给Comparator的变量
//多态引用
/* Comparator c = new Comparator(){
@Override
public int compare(Object o1, Object o2) {
Circle c1 = (Circle) o1;
Circle c2 = (Circle) o2;
if(c1.getRadius() > c2.getRadius()){
return 1;
}else if(c1.getRadius() < c2.getRadius()){
return -1;
}
return 0;
}
};
System.out.println(c.compare(new Circle(1), new Circle(2)));*/
Circle[] all = new Circle[3];
all[0] = new Circle(3);
all[1] = new Circle(2);
all[2] = new Circle(1);
//匿名内部类的匿名对象作为实参使用
Arrays.sort(all, new Comparator(){
@Override
public int compare(Object o1, Object o2) {
Circle c1 = (Circle) o1;
Circle c2 = (Circle) o2;
if(c1.getRadius() > c2.getRadius()){
return 1;
}else if(c1.getRadius() < c2.getRadius()){
return -1;
}
return 0;
}
});
}
}
/*class RadiusComparator implements Comparator{
@Override
public int compare(Object o1, Object o2) {
Circle c1 = (Circle) o1;
Circle c2 = (Circle) o2;
if(c1.getRadius() > c2.getRadius()){
return 1;
}else if(c1.getRadius() < c2.getRadius()){
return -1;
}
return 0;
}
}*/
class Circle{
private double radius;
public Circle(double radius) {
super();
this.radius = radius;
}
public double getRadius() {
return radius;
}
public void setRadius(double radius) {
this.radius = radius;
}
@Override
public String toString() {
return "Circle [radius=" + radius + "]";
}
}