目录
1. 笔记
1.1 接口
1.接口 usb接口,type-c接口... usb接口的规范又是哪来的?有人定制了这个规范,然后厂商按照这个规范生产 接口-->定义规则 1.1 接口的语法 【修饰符】 interface 接口名{} -->类似于类的语法 定义接口的修饰符和类的修饰符知识点一样 1.2 分类 接口是支持多态的! JDK1.8之前 ① 所有个属性都是公有静态常量 ② 所有的方法都是公有的抽象方法 ③ 接口是不能实例化对象的,也没有构造器 ④ 所以接口只能作为父级使用 ⑤ 类可以实现多个接口,但是类需要实现接口中所有的抽象方法 ⑥ 接口是可以继承多个接口的 JDK1.8 新增了两种类型的方法(可以有代码体) a. 静态方法 static void staticMethod(){} 使用方式:接口名.staticMethod(); 一般就是使用在工具方法上 b. 默认方法 default void defaultMethod(){}; 使用方式:实现类的对象.defaultMethod(); 默认方法是可以被实现类重写! 冲突: (1)实现类类是可以实现接口,同时也可以继承父类 父接口和父类中有相同的方法,默认调用父类的(亲爹优先) (2) 实现类是可以实现多个接口的 父接口1和父接口2有相同的默认方法! 实现类必须重写该方法! ① 自己真正的重写 ② 选择其中的一个、几个或者都选 父接口.super.方法 1.3 特点 a.接口不能实例化对象 b.只能作为父级(父接口) 子类继承父类 实现类实现父接口 c.实现类实现父接口,并实现父接口中所有的抽象方法 public class Aircraft implements Fly{抽象方法实现} d.如果类有父接口,还可以有父类吗? 可以的 public class Aircraft extends Person implements Fly,Attack{} 1.4关系 a.类与类之间:单继承 b.类与接口之间:多实现 c.接口与接口之间:多继承 2. 经典的接口 2.1 java.lang.Comparable --> 自然排序 抽象方法--> int compareTo(Object obj) 功能:this和obj比对大小! 返回值: 正数说明this大 负数说明this小 0说明一般大 对比两个对象的大小!(指定根据什么比) 在需要对比的类上实现该接口! ① 在Person类上实现该接口 ② 实现该接口的抽象方法 ③ 方法体中实现比较规则 2.2 java.util.Comparator --> 定制排序 int compare(Object o1,Object o2) 注意:定制排序的优先级高于自然排序 自我练习: 创建一个Person类,定义一些属性,然后创建Person数组,存储Person对象 对数组排序(自己定义根据什么排序,自己定义排序规则) a. Comparable的使用 compareTo方法的功能 b. 理解为何要求排序的类必须实现Comparable接口 c. 体会接口的好处!
1.2 内部类
1. 内部类 类的五大成员->成员变量、成员方法、构造器、初始化块、内部类 分类: 成员内部类 ★ 静态成员内部类 方法(局部)内部类 匿名内部类 ★ 1.1 匿名内部类 (只用一次) 语法:new 类、抽象类、接口(){} 解析:大括号就相当于是类的子类、接口的实现类的大括号 优缺点: 优点:简单一些(省略了创建类) 缺点:复用性很差 JDK1.8 Lambda表达式对部分匿名内部类简化 练习: 创建Person类,创建若干个属性,通过定制排序为Person数组排序! 要求排序规则使用匿名内部类! 1.2 成员内部类 位置:类体中(和其他成员在同级别的位置) class文件:外部类$内部类.class 语法:【修饰符】 class 类名{} 成员:五大成员都可以存在!但是不可以有静态资源! 修饰符:四个访问修饰符都可以修饰!abstract final都可以单独修饰 使用: a. 内部类如何使用外部类的资源! 完全可以直接访问! b. 外部类如何使用内部类资源! 需要实例化内部类的对象,使用 c. 外部其它类(测试类)如何使用内部类 需要实例化内部类的对象在使用! (1)需要外部类对象 Outher outher=new Outher(); (2)在实例化内部类对象 Outher.Inner1 inner1=outher.new Inner1(); 冲突问题解决: 外部类和内部类的属性或者方法重名! this.内容 this是当前对象 Outher.this.内容 Outher.this外部类的对象 this是依赖于Outher.this的! 1.3 静态成员内部类 位置:类体中 class: Outher$Inner2.class 语法:【修饰符】 static class 类名{} 成员:五大成员都可以存在!包括静态资源! 修饰符:四个访问修饰符都可以修饰!abstract final都可以单独修饰 使用: a. 内部类如何使用外部类的资源! 静态资源可以直接使用,非静态的实例化对象使用 b. 外部类如何使用内部类资源! 如果是静态资源,可以直接使用类名调用 如果是非静态的,实例化对象调用 c. 外部其它类(测试类)如何使用内部类 不在依赖于外部类的对象了 直接实例化对象即可: Outher.Inner2 inner2=new Outher.Inner2(); 冲突问题解决: 外部类的静态资源,和内部类的普通资源如果重复! 有办法区分,静态资源可以通过类名调用! 1.4 方法(局部)内部类 位置:在某个局部(方法内) class: Outher$1Inner3.class 语法:【修饰符】class 类名{} 成员:五大成员都可以存在!但是不包括静态资源! 修饰符:abstract final可以单独修饰,访问修饰符不可以 使用: a. 内部类如何使用外部类的资源! 直接使用 b. 外部类如何使用内部类资源! 当前局部,可以通过实例化对象的形式访问 其他地方无法访问! c. 外部其它类(测试类)如何使用内部类 访问不到 冲突问题: 外部类和内部类属性重名,默认就近原则 this:当前对象 Outher.this 外部类对象 如果当前局部,存在局部变量,在内部类使用该变量的话! 默认会变为常量!
2. 练习
2.1 接口练习
练习一:
1、声明一个LiveAble接口
包含两个抽象方法:
void eat();
void breathe();
包含默认方法 default void sleep(),实现为打印“静止不动”
包含静态方法 static void drink(),实现为“喝水”
2、声明动物Animal类,实现LiveAble接口。
void eat();实现为“吃东西”,
void breathe();实现为"吸入氧气呼出二氧化碳"
void sleep()重写为”闭上眼睛睡觉"
3、声明植物Plant类,实现LiveAble接口。
void eat();实现为“吸收营养”
void breathe();实现为"吸入二氧化碳呼出氧气"
4、在测试类中,分别创建两个实现类的对象,调用对应的方法。通过接口名,调用静态方法
定义接口
public interface LiveAble {
// 定义抽象方法
public abstract void eat();
public abstract void breathe();
//定义默认方法
public default void sleep(){
System.out.println("静止不动");
}
//定义静态方法
public static void drink(){
System.out.println("喝水");
}
}
定义实现类
public Animal implements LiveAble {
//重写/实现接口的抽象方法
@Override
public void eat() {
System.out.println("吃东西");
}
//重写/实现接口的抽象方法
@Override
public void breathe(){
System.out.println("吸入氧气呼出二氧化碳");
}
//重写接口的默认方法
@Override
public void sleep() {
System.out.println("闭上眼睛睡觉");
}
}
public class Plant implements LiveAble {
//重写/实现接口的抽象方法
@Override
public void eat() {
System.out.println("吸收营养");
}
//重写/实现接口的抽象方法
@Override
public void breathe(){
System.out.println("吸入二氧化碳呼出氧气");
}
}
定义测试类
public class InterfaceDemo {
public static void main(String[] args) {
// 创建实现类(子类)对象
Animal a = new Animal();
// 调用实现后的方法
a.eat();
a.sleep();
a.breathe();
//创建实现类(子类)对象
Plant p = new Plant();
p.eat();
p.sleep();
p.breathe();
//通过接口调用静态方法
LiveAble.drink();
}
}
输出结果:
吃东西
闭上眼睛睡觉
吸入氧气呼出二氧化碳
吸收营养
静止不动
吸入二氧化碳呼出氧气
喝水
2.2 接口的多实现练习
练习一:
1、声明第一个接口Runner,包含抽象方法:void run()
2、声明第二个接口Swimming,包含抽象方法:void swim()
3、声明兔子类,实现Runner接口
4、声明乌龟类,实现Runner接口和Swimming接口
interface Runner{
void run();
}
interface Swimming{
void swim();
}
class Rabbit implements Runner{
@Override
public void run() {
System.out.println("兔子跑得快");
}
}
class Tortoise implements Runner,Swimming{
@Override
public void swim() {
System.out.println("乌龟游得快");
}
@Override
public void run() {
System.out.println("乌龟跑的慢");
}
}
2.3 经典接口部分练习
练习一:冒泡排序
声明一个Employee员工类,包含编号、姓名、薪资,实现Comparable接口,要求,按照薪资比较大小,如果薪资相同,按照编号比较大小。
声明一个测试类TestEmployee类,在main中创建Employee[]数组,长度为5,并且存储5个员工对象,现在要求用冒泡排序,实现对这个数组进行排序,遍历结果。
class Employee implements Comparable{
private int id;
private String name;
private double salary;
public Employee(int id, String name, double salary) {
super();
this.id = id;
this.name = name;
this.salary = salary;
}
public Employee() {
super();
}
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;
}
@Override
public String toString() {
return "Employee [id=" + id + ", name=" + name + ", salary=" + salary + "]";
}
@Override
public int compareTo(Object o) {
Employee emp = (Employee) o;
if(this.getSalary() != emp.getSalary()){
return Double.compare(this.getSalary(), emp.getSalary());
}
return this.id - emp.id;
}
}
public class TestComparable {
public static void main(String[] args) {
Employee[] arr = new Employee[5];
arr[0] = new Employee(1,"张三",13000);
arr[1] = new Employee(2,"李四",13000);
arr[2] = new Employee(3,"王五",14000);
arr[3] = new Employee(4,"赵六",7000);
arr[4] = new Employee(5,"钱七",9000);
//原顺序
System.out.println("员工列表:");
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
//冒泡排序
for (int i = 1; i < arr.length; i++) {
for (int j = 0; j < arr.length-i; j++) {
//因为Employee类型实现了Comparable接口,所以有compareTo()方法
if(arr[j].compareTo(arr[j+1])>0){
Employee temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}
}
}
System.out.println("排序后员工列表:");
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
}
}
练习二:自定义数组排序工具类
自定义一个数组工具类MyArrays,它包含一个静态方法,可以给任意对象数组用冒泡排序实现从小到大排序,该怎么定义这个方法呢?
class MyArrays{
public static void sort(Object[] arr){
//冒泡排序
for (int i = 1; i < arr.length; i++) {
for (int j = 0; j < arr.length-i; j++) {
//将arr[j]强制为Comparable接口类型,目的是调用compareTo方法
//当然如果数组的元素没有实现这个接口,那么将会发生ClassCastException
Comparable c = (Comparable) arr[j];
if(c.compareTo(arr[j+1])>0){
Object temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}
}
}
}
}
使用自定义的MyArrays数组工具类,给练习1的员工数组进行排序
public class TestComparable {
public static void main(String[] args) {
Employee[] arr = new Employee[5];
arr[0] = new Employee(1,"张三",13000);
arr[1] = new Employee(2,"李四",13000);
arr[2] = new Employee(3,"王五",14000);
arr[3] = new Employee(4,"赵六",7000);
arr[4] = new Employee(5,"钱七",9000);
//原顺序
System.out.println("员工列表:");
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
//要求Employee类型必须实现Comparable接口,否则将发生ClassCastException异常
MyArrays.sort(arr);
System.out.println("排序后员工列表:");
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
}
}
java.util.Arrays数组工具类的public static void sort(Object[] a)就是这么实现的,只不过它使用的排序算法是效率更高快排,而不是冒泡排序,但是无论哪种排序算法,最终都要涉及到两个元素的比较大小,都需要通过元素调用compareTo()方法 。
2.4 匿名内部类练习
练习一:
声明一个Employee员工类,包含编号、姓名、薪资,
声明一个测试类,在main中,创建Employee[]数组,长度为5,显示原来顺序结果
调用java.util.Arrays数组工具类的排序方法public static void sort(Object[] a, Comparator c)对数组的元素进行排序,用匿名内部类的对象给c形参传入按照薪资比较大小的定制比较器对象。并显示排序后结果
调用java.util.Arrays数组工具类的排序方法public static void sort(Object[] a, Comparator c)对数组的元素进行排序,用匿名内部类的对象给c形参传入按照编号比较大小的定制比较器对象。并显示排序后结果
员工类代码
class Employee{
private int id;
private String name;
private double salary;
public Employee(int id, String name, double salary) {
super();
this.id = id;
this.name = name;
this.salary = salary;
}
public Employee() {
super();
}
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;
}
@Override
public String toString() {
return "Employee [id=" + id + ", name=" + name + ", salary=" + salary + "]";
}
}
测试类
public class TestInner {
public static void main(String[] args) {
Employee[] arr = new Employee[5];
arr[0] = new Employee(1,"张三",13000);
arr[1] = new Employee(3,"王五",14000);
arr[2] = new Employee(2,"李四",13000);
arr[3] = new Employee(4,"赵六",7000);
arr[4] = new Employee(5,"钱七",9000);
//原顺序
System.out.println("员工列表:");
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
Arrays.sort(arr, new Comparator() {
@Override
public int compare(Object o1, Object o2) {
Employee e1 = (Employee) o1;
Employee e2 = (Employee) o2;
return Double.compare(e1.getSalary(), e2.getSalary());
}
});
System.out.println("按照薪资排序后员工列表:");
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
Arrays.sort(arr, new Comparator() {
@Override
public int compare(Object o1, Object o2) {
Employee e1 = (Employee) o1;
Employee e2 = (Employee) o2;
return e1.getId() - e2.getId();
}
});
System.out.println("按照编号排序后员工列表:");
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
}
}
练习二:
(1)声明一个抽象类Father,包含抽象方法:public abstract void method();
(2)用匿名内部类继承Father,并重写抽象方法,打印“hello baby" 并调用子类对象method方法
public abstract class Father{
public abstract void method();
}
public class TestExer1 {
public static void main(String[] args) {
new Father(){
@Override
public void method() {
System.out.println("hello 孩子");
}
}.method();
}
}
练习三:
(1)声明一个员工类Triangle三角形,有属性:a,b,c表示三条边
(2)在测试类中创建Triangle数组
(3)分别调用Arrays.sort(数组,Comparator),用匿名内部类实现按照编号周长排列
(4)分别调用Arrays.sort(数组,Comparator),用匿名内部类实现按照薪资面积排列
public class Triangle {
private double a;
private double b;
private double c;
public Triangle(double a, double b, double c) {
super();
this.a = a;
this.b = b;
this.c = c;
}
public Triangle() {
super();
}
public double getA() {
return a;
}
public void setA(double a) {
this.a = a;
}
public double getB() {
return b;
}
public void setB(double b) {
this.b = b;
}
public double getC() {
return c;
}
public void setC(double c) {
this.c = c;
}
@Override
public String toString() {
return "Triangle [a=" + a + ", b=" + b + ", c=" + c + "]";
}
public double getPerimeter(){
return a+b+c;
}
public double getArea(){
double p = getPerimeter()/2;
return Math.sqrt(p*(p-a)*(p-b)*(p-c));
}
}
public class TestExer2 {
public static void main(String[] args) {
Triangle[] arr = new Triangle[3];
arr[0] = new Triangle(6, 1, 6);
arr[1] = new Triangle(3, 4, 5);
arr[2] = new Triangle(6, 6, 6);
System.out.println("原来的顺序:");
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
System.out.println("--------------------");
System.out.println("按照周长排序:");
Arrays.sort(arr, new Comparator() {
@Override
public int compare(Object o1, Object o2) {
Triangle t1 = (Triangle) o1;
Triangle t2 = (Triangle) o2;
return Double.compare(t1.getPerimeter(), t2.getPerimeter());
}
});
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
System.out.println("--------------------");
System.out.println("按照面积排序:");
Arrays.sort(arr, new Comparator() {
@Override
public int compare(Object o1, Object o2) {
Triangle t1 = (Triangle) o1;
Triangle t2 = (Triangle) o2;
return Double.compare(t1.getArea(), t2.getArea());
}
});
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
}
}
练习四:
public interface Predicate {
public abstract boolean test(Object obj);
}
public class Employee{
private int id;
private String name;
private int age;
private double salary;
public Employee() {
super();
}
public Employee(int id, String name, int age, double salary) {
super();
this.id = id;
this.name = name;
this.age = age;
this.salary = salary;
}
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 int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
@Override
public String toString() {
return "Employee [id=" + id + ", name=" + name + ", age=" + age + ", salary=" + salary + "]";
}
}
public class EmployeeService {
private Employee[] arr;
public EmployeeService() {
arr = new Employee[5];
arr[0] = new Employee(4, "李四", 24, 24000);
arr[1] = new Employee(3, "张三", 23, 13000);
arr[2] = new Employee(5, "王五", 25, 15000);
arr[3] = new Employee(1, "赵六", 27, 17000);
arr[4] = new Employee(2, "钱七", 16, 6000);
}
public Employee[] get(Predicate p){
Employee[] result = new Employee[arr.length] ;
int total = 0;
for (int i = 0; i < arr.length; i++) {
if(p.test(arr[i])){
result[total++] = arr[i];
}
}
return Arrays.copyOf(result, total);
}
}
public class TestExer5 {
public static void main(String[] args) {
EmployeeService es = new EmployeeService();
//(1)所有员工对象
Employee[] employees = es.get(new Predicate(){
@Override
public boolean test(Object obj) {
return true;
}
});
for (int i = 0; i < employees.length; i++) {
System.out.println(employees[i]);
}
System.out.println("============================");
// (2)所有年龄超过25的员工
employees = es.get(new Predicate(){
@Override
public boolean test(Object obj) {
Employee emp = (Employee) obj;
return emp.getAge()>25;
}
});
for (int i = 0; i < employees.length; i++) {
System.out.println(employees[i]);
}
//....
}
}
2.5 非静态成员内部类练习
练习一(语法练习题):
声明一个身体Body类,包含一个boolean类型的属性live,初始化为true,表示活着。属性私有化,提供get/set方法。
声明一个身体Body的内部类Heart,包含void jump()方法,当live为true时,打印“心脏在跳动”,否则打印“心脏停止跳动"。
声明一个测试类,在测试类的主方法中,创建身体和心脏的对象,调用心脏对象的jump()方法,然后调用身体对象的setLive()方法,设置为false后,再调用心脏对象的jump()方法查看结果。
思考:如何保证一个Body对象,同一个Heart对象,不同的Body对象,不同的Heart对象呢?
public class Person {
private boolean live = true;
class Heart {
public void jump() {
// 直接访问外部类成员
if (live) {
System.out.println("心脏在跳动");
} else {
System.out.println("心脏不跳了");
}
}
}
public boolean isLive() {
return live;
}
public void setLive(boolean live) {
this.live = live;
}
}
测试类
public class InnerDemo {
public static void main(String[] args) {
// 创建外部类对象
Person p = new Person();
// 创建内部类对象
Heart heart = p.new Heart();
// 调用内部类方法
heart.jump();
// 调用外部类方法
p.setLive(false);
// 调用内部类方法
heart.jump();
}
}
输出结果:
心脏在跳动
心脏不跳了
练习二(简单面试题):
判断如下代码的运行结果:
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);
}
}
练习三(高难度面试题):
代码填空题:
public class TestInner{
public static void main(String[] args){
Outer.Inner in = new Sub();
in.method();//输出 hello inner
}
}
class Outer {
abstract class Inner{
abstract void method();
}
}
class Sub ________(1)__________{
______(2)多行代码_______________
}
参考答案:
public class TestInner{
public static void main(String[] args){
Outer.Inner in = new Sub();
in.method();//输出 hello inner
}
}
class Outer {
abstract class Inner{
abstract void method();
}
}
class Sub extends Outer.Inner{
static Outer out = new Outer();
Sub(){
out.super();
}
@Override
void method() {
System.out.println("hello inner");
}
}
2.6 静态内部类练习
练习一:
1、声明一个外部类叫做"汉献帝",包含私有静态的String类型的变量“玉玺”,赋值为“皇帝玉玺”。
2、声明一个静态内部类叫做“董卓”,包含静态方法order(),打印"董卓拿了皇帝玉玺直接发号施令"
3、在测试类的main中,调用order方法
public class TestInner{
public static void main(String[] args){
HanXianDi.DongZhuo.order();
}
}
class HanXianDi{
private static String yuXi = "皇帝玉玺";
static class DongZhuo{
public static void order(){
System.out.println("董卓拿了"+ yuXi +"直接发号施令");
}
}
}