目录
1.接口
2.接口的好处(重点):
2.应用案例:班级学生信息管理模块
3.接口新增的3种方法
4.接口的多继承
5.内部类:
匿名内部类(重点)
拓展:搞清楚匿名内部类在开发中的真实使用场景
6.枚举:
拓展:抽象枚举
使用枚举类实现单例设计模式
7.泛型
泛型类
泛型接口
泛型方法
泛型的上下限
注意:泛型的擦除问题和注意事项
使用interface关键字定义的一种结构, JDK 8之前,接口中只能定义成员变量和成员方法。
public interface 接口名 {
// 成员变量(常量)
// 成员方法(抽象方法)
}
public interface A {
// 成员变量(常量)
String SCHOOL_NAME = "黑马程序员";
// 成员方法(抽象方法)
void test();
}
public class Test {
public static void main(String[] args) {
// 目标:认识接口。
System.out.println(A.SCHOOL_NAME);
// A a = new A();
}
}
注意1.接口不能创建对象,接口是用来被类实现(implements)的,实现接口的类称为实现类。
修饰符 class 实现类 implements 接口1,接口2,接口3,...{
}
2.一个接口可以继承多个接口,实现类实现多个接口,必须重写完全部接口的全部抽象方法,否则实现类需要定义成抽象类。
public interface B {
void testb1();
void testb2();
}
public interface C {
void testc1();
void testc2();
}
// 实现类
public class D implements B, C{
@Override
public void testb1() {
}
@Override
public void testb2() {
}
@Override
public void testc1() {
}
@Override
public void testc2() {
}
}
public class Test {
public static void main(String[] args) {
D d = new D();
1.弥补了类单继承的不足,一个类同时可以实现多个接口。
2.让程序可以面向接口编程,这样程序员就可以灵活方便的切换各种业务实现。
import com.itheima.d5_abstract2.Animal;
import com.itheima.d5_abstract2.Cat;
public class Test {
public static void main(String[] args) {
// 目标:搞清楚使用接口的好处。
Driver s = new A();
s.drive();
Driver d = new A();
d.drive();
Animal a = new Cat();
a.cry();
}
}
class B implements Driver{
@Override
public void drive() {
}
}
class A extends Student implements Driver, Singer{
@Override
public void drive() {
}
@Override
public void sing() {
}
}
class Student{
}
interface Driver{
void drive();
}
interface Singer{
void sing();
public class ClassManager {
private ArrayList students = new ArrayList<>();
//private StudentOperator studentOperator = new StudentOperatorImpl1();
private StudentOperator studentOperator = new StudentOperatorImpl2();
public ClassManager(){ //构造器 通过构造器初始化班级对象
//创建学生对象
students.add(new Student("迪丽热巴", '女', 99));
students.add(new Student("古力娜扎", '女', 100));
students.add(new Student("马尔扎哈", '男', 80));
students.add(new Student("卡尔扎巴", '男', 60));
}
// 打印全班全部学生的信息
public void printInfo(){
studentOperator.printAllInfo(students);
}
// 打印全班全部学生的平均分
public void printScore(){
studentOperator.printAverageScore(students);
}
}
public interface StudentOperator {
void printAllInfo(ArrayList students); //抽样方法
void printAverageScore(ArrayList students);
}
//实现类
public class StudentOperatorImpl1 implements StudentOperator{
//抽样方法全部重写 alt+回车
@Override
public void printAllInfo(ArrayList students) {
System.out.println("----------全班全部学生信息如下--------------");
for (int i = 0; i < students.size(); i++) {
Student s = students.get(i);
System.out.println("姓名:" + s.getName() + ", 性别:" + s.getSex() + ", 成绩:" + s.getScore());
}
System.out.println("-----------------------------------------");
}
@Override
public void printAverageScore(ArrayList students) {
double allScore = 0.0;
for (int i = 0; i < students.size(); i++) {
Student s = students.get(i);
allScore += s.getScore();
}
System.out.println("平均分:" + (allScore) / students.size());
}
}
//第二套方案
public class StudentOperatorImpl2 implements StudentOperator{
@Override
public void printAllInfo(ArrayList students) {
System.out.println("----------全班全部学生信息如下--------------");
int count1 = 0; //记录男生人数
int count2 = 0; //记录女生人数
for (int i = 0; i < students.size(); i++) {
Student s = students.get(i);
System.out.println("姓名:" + s.getName() + ", 性别:" + s.getSex() + ", 成绩:" + s.getScore());
if(s.getSex() == '男'){
count1++;
}else {
count2 ++;
}
}
System.out.println("男生人数是:" + count1 + ", 女士人数是:" + count2);
System.out.println("班级总人数是:" + students.size());
System.out.println("-----------------------------------------");
}
@Override
public void printAverageScore(ArrayList students) {
double allScore = 0.0;
double max = students.get(0).getScore(); //第一个学生成绩
double min = students.get(0).getScore();
for (int i = 0; i < students.size(); i++) {
Student s = students.get(i);
if(s.getScore() > max) max = s.getScore();
if(s.getScore() < min) min = s.getScore();
allScore += s.getScore();
}
System.out.println("学生的最高分是:" + max);
System.out.println("学生的最低分是:" + min);
System.out.println("平均分:" + (allScore - max - min) / (students.size() - 2));
}
}
public class Test {
public static void main(String[] args) {
// 目标:完成班级学生信息管理的案例。
ClassManager clazz = new ClassManager();
clazz.printInfo();
clazz.printScore();
}
}
public class Student {
private String name;
private char sex;
private double score;
public Student() {
}
public Student(String name, char sex, double score) {
this.name = name;
this.sex = sex;
this.score = score;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public char getSex() {
return sex;
}
public void setSex(char sex) {
this.sex = sex;
}
public double getScore() {
return score;
}
public void setScore(double score) {
this.score = score;
}
}
1.默认方法:必须使用default修饰,默认会被public修饰
实例方法:对象的方法,必须使用实现类的对象调用
2.私有方法:必须使用private修饰(jdk9开始),只能在接口内部被调用
实例方法:对象的方法。
3. 静态方法:必须使用static修饰,默认会被public修饰
接口名.方法();
public interface A {
/*1.默认方法:必须使用default修饰,默认会被public修饰
实例方法:对象的方法,必须使用实现类的对象访问*/
default void test1() {
System.out.println("======默认方法=======");
test2();
}
/*
2.私有方法:必须使用private修饰(jdk9开始)
实例方法:对象的方法。
*/
private void test2(){
System.out.println("=========私有方法=======");
}
/*
3. 静态方法:必须使用static修饰,默认会被public修饰
*/
static void test3(){
System.out.println("==静态方法=======");
}
}
public class B implements A{
}
public class Test {
public static void main(String[] args) {
//掌握接口3种方法
B b =new B();
b.test1();
A.test3();
}
}
一个接口可以继承多个接口
作用:便于实现类去实现
是类中的五大成分之一(成员变量、方法、构造器、内部类、代码块),如果一个类定义在另一个类的内部,这个类就是内部类。
1.成员内部类(了解):类中一个普通成员,类似于普通成员变量,成员方法
成员内部类中访问其他成员的特点:
1、同样可以直接访问外部类的实例成员、静态成员。
2、拿到当前外部类对象,格式是:外部类名.this 。
2.静态内部类(了解):有static修饰的内部类,属于内部类自己持有
可以直接访问外部类的静态成员,不可以直接访问外部类的实例成员
是一种特殊的局部内部类 ,所谓匿名:指的是程序员不需要为这个类声明名字。
new 类或接口(参数值...){
类体(一般是方法重写);
};
特点:匿名内部类本质就是一个子类,并会立即创建出一个子类对象。
作用:用于更方便的创建一个子类对象。
通常作为一个参数传输给方法。
public class Test {
public static void main(String[] args) {
// 目标:认识匿名内部类,并掌握其作用。// 1、把这个匿名内部类编译成一个子类,然后会立即创建一个子类对象出来。
Animal a = new Animal(){
@Override
public void cry() {
System.out.println("猫喵喵喵的叫~~~");
}
};
a.cry();
}
}
abstract class Animal{
public abstract void cry();
}
使用场景:
Test2类
public class Test2 {
public static void main(String[] args) {
// 目标:掌握匿名的常见使用场景。
go(new Swimming(){
@Override
public void swim() {
System.out.println("狗游泳飞快~~~~");
}
});
}
// 设计一个方法,可以接收swimming接口的一切实现类对象进来参加游泳比赛。
public static void go(Swimming s){
System.out.println("开始-----------------------");
s.swim();
}
}
//猫和狗都参加游泳比赛 实现
interface Swimming{
void swim();
}
public class Test {
public static void main(String[] args) {
//GUI编程
//1.创建窗口
JFrame win = new JFrame("登录界面");
JPanel panel = new JPanel();//桌布
win.add(panel);//把桌布加入到窗口当中去
JButton btn = new JButton("窗口");
panel.add(btn);
//给按钮绑定单击事件(单击事件监听器)
// btn.addActionListener(new ActionListener() {
// @Override
// public void actionPerformed(ActionEvent e) {
// JOptionPane.showMessageDialog(win,"登录一下");
// }
// });
//简化代码
btn.addActionListener(e -> JOptionPane.showMessageDialog(win,"登录一下"));
win.setSize(408,408);
win.setLocationRelativeTo(null);//居中
win.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);//关闭窗口,退出程序
win.setVisible(true);//显示出来
}
}
是一种特殊类。
修饰符 enum 枚举类名{
名称1,名称2..;
其他成员...
}
注意:1.枚举类的第一行必须罗列的是枚举对象的名字,都是常量 ,并且每个常量记住的都是枚举类的一个对象。
2.构造器都是私有的,枚举类不能创建对象,是最终类,不能被继承
public enum A {
//注意:枚举类的第一行必须罗列的是枚举对象的名字,都是常量
X, Y, Z;
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public class Test {
public static void main(String[] args) {
//目标 认识枚举
A a1 =A.X;
System.out.println(a1); //X
//枚举类提供一个一些额外的API
A[] as = A.values();//拿到全部对象
A a3 = A.valueOf("Z");
System.out.println(a3.name()); //Z
System.out.println(a3.ordinal()); //索引
}
}
public enum B {
X() {
@Override
public void go() {
}
},Y("站三"){
@Override
public void go() {
System.out.println(getName()+ "再跑--");
}
};
private String name;
B() {
}
B(String name) {
this.name = name;
}
public abstract void go();
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public class Test{
main
B y = B.Y;
y.go();
}
public enum C {
X; //单例
}
常见应用场景:用来表示一组信息,然后作为参数进行传输
public enum Constant2 {
BOY,GIRL;
}
public class Test {
public static void main(String[] args) {
//目标:掌握枚举的应用场景:做信息标志和分类
check(Constant.BOY);
}
public static void check(Constant2 sex){
switch (sex){
case BOY:
System.out.println("展示一些美女");
break;
case GIRL:
System.out.println("展示一些帅哥");
break;
}
}
}
定义类,接口,方法时,同时声明了一个或者多个类型变量(
public class ArrayList
{ . . .
}
作用:泛型提供了在编译阶段约束所能操作的数据类型,并自动进行检查的能力!这样可以避免强制类型转换,及其可能出现的异常。
泛型的本质:把具体的数据类型作为参数传给类型变量。
ArrayList list = new ArrayList<>();
list.add("java1");
list.add("java2");
list.add("java3");
//list.add("new Cat");
for (int i = 0; i < list.size(); i++) {
String e = list.get(i);
System.out.println(e);
}
}
修饰类 class 类名<类型变量,类型变量,..>{
}
// 泛型类
public class MyArrayList {
private Object[] arr = new Object[10];
private int size; // 记录当前位置的
public boolean add(E e){
arr[size++] = e;
return true;
}
public E get(int index){ //根据索引查数据类型
return (E) arr[index]; //强转结果
}
}
//
public class MyClass2 {
public void put(E e, T t){
}
}
//
public class MyClass3 {
}
public class Test {
public static void main(String[] args) {
// 目标:掌握泛型类的定义和使用。
MyArrayList list = new MyArrayList<>();
list.add("java1");
list.add("java2");
String ele = list.get(1);
System.out.println(ele);
MyClass2 c2 = new MyClass2<>();
// MyClass3 c3 = new MyClass3<>(); // 报错
MyClass3 c4 = new MyClass3<>();
MyClass3 c5 = new MyClass3<>();
}
}
用来给实现类实现的,可以声明数据类型上来,然后实现类重写这些方法,都将针对该类型操作
修饰符 interface 接口名<类型变量,类型变量,..>{
}
泛型变量建议用大写的英文字母。常用有:E,T, K, V等
public class Test {
public static void main(String[] args) {
//掌握泛型接口定义和使用
//系统需要处理学生和老师的数据,需要提供2个功能,保存对象数据,根据名称查询数据
}
}
import java.util.ArrayList;
//泛型接口
public interface Data {
//public interface Data { //也可以继承
void add(T t);
ArrayList getByName(String name);
}
//老师类
public class Teacher {
}
//实现类
public class TeacherData implements Data{
@Override
public void add(Teacher teacher) {
}
@Override
public ArrayList getByName(String name) {
return null;
}
}
//学生类
public class Student {
}
//实现类
public class StudentData implements Data{ //alt+回车
@Override
public void add(Student student) {
}
@Override
public ArrayList getByName(String name) {
return null;
}
}
修饰符<类型变量,类型变量,...> 返回值类型 方法名(形参列表){
}
public static
void test(T t){ }
public class Test {
public static void main(String[] args) {
// 目标:掌握泛型方法的定义和使用。
String rs = test("java");
System.out.println(rs);
Dog d = test(new Dog());
System.out.println(d);
// 需求:所有的汽车可以一起参加比赛。
ArrayList cars = new ArrayList<>();
cars.add(new BMW());
cars.add(new BENZ());
go(cars);
ArrayList bmws = new ArrayList<>();
bmws.add(new BMW());
bmws.add(new BMW());
go(bmws);
ArrayList benzs = new ArrayList<>();
benzs.add(new BENZ());
benzs.add(new BENZ());
go(benzs);
// ArrayList dogs = new ArrayList<>();
// dogs.add(new Dog());
// dogs.add(new Dog());
// go(dogs);
}
// ? 通配符,在使用泛型的时候可以代表一切类型 ? extends Car(上限) ? super Car(下限)
public static void go(ArrayList extends Car> cars){
}
// public static void go(ArrayList cars){
//
// }
// 泛型方法
public static T test(T t){
return t;
}
}
? 通配符,在使用泛型的时候可以代表一切类型 ?extends Car(上限) ? super Car(下限)
?,可以在“使用泛型”的时候代表一切类型;E T K V 是定义泛型的时候使用
泛型上限: ? extends Car: ? 能接收的必须是Car或者其子类 。
泛型下限: ? super Car : ? 能接收的必须是Car或 者其父类。
1.泛型是工作在编译阶段的,一旦程序编译成class文件,class文件中就不存在泛型了,这就是泛型擦除。
ArrayList
list = new ArrayList<>();
list.add("java1");
list.add("java2");
list.add("java3");
String rs = list.get(2);
System.out.println(rs);
2.泛型不支持基本数据类型,只能支持对象类型(引用数据类型)。
// ArrayList
list1 = new ArrayList<>();
// ArrayListlist2 = new ArrayList<>();
ArrayListlist1 = new ArrayList<>();
list1.add(12);ArrayList
list2 = new ArrayList<>();
list2.add(23.3);double a = 0.1;
double b = 0.2;
double c = a + b;
System.out.println(a);
BigDecimal a1 = new BigDecimal(0.1);