青海省住房和城乡建设厅网站,天津做淘宝网站,网站 被黑,wordpress 标签手册Java基础 - 6 - 面向对象#xff08;一#xff09;-CSDN博客 二. 面向对象高级
2.1 static static叫做静态#xff0c;可以修饰成员变量、成员方法
2.1.1 static修饰成员变量 成员变量按照有无static修饰#xff0c;分为两种#xff1a;类变量、实例变量#xff08;对象…Java基础 - 6 - 面向对象一-CSDN博客 二. 面向对象高级
2.1 static static叫做静态可以修饰成员变量、成员方法
2.1.1 static修饰成员变量 成员变量按照有无static修饰分为两种类变量、实例变量对象的变量 类变量静态成员变量有static修饰属于类与类一起加载一次在计算机内存里只有一份会被类的全部对象共享 类名.类变量 实例变量对象的变量无static修饰属于每个对象的每个对象都有一份 对象.实例变量 //demo
public class demo {public static void main(String[] args) {//类变量 通过类名.类变量的方式访问推荐Student.name 张三;//对象.类变量不推荐Student s1 new Student();s1.name 李四;Student s2 new Student();s2.name 王五;//因为类变量在计算机中只有一份被共享System.out.println(Student.name); //王五System.out.println(s1.name); //王五System.out.println(s2.name); //王五//实例变量s1.age 20;s2.age 22;System.out.println(s1.age); //20System.out.println(s2.age); //22}
}//Student
public class Student {//类变量static String name;//实例变量int age;
} 类变量的应用场景 在开发中如果某个数据只需要一份且希望能够被共享访问、修改则该数据可以定义为类变量来记住 //demo
public class demo {public static void main(String[] args) {User u1 new User();User u2 new User();User u3 new User();User u4 new User();System.out.println(User.number); //4}
}//User
public class User {//类变量通常用public修饰public static int number;public User(){//注意在同一个类中访问自己的类变量才可以直接不写类名User.number; //在这里可以直接写成 number}
}
2.1.2 static修饰成员方法 成员方法的分类按照有无static修饰可以分为类方法和实例方法 类方法有static修饰的成员方法属于类 实例方法无static修饰的成员方法属于对象 //demo
public class demo {public static void main(String[] args) {//类方法的使用//类名.类方法推荐Student.printHelloWorld();//对象.类方法不推荐Student s1 new Student();s1.printHelloWorld();//实例方法的使用s1.score70;s1.printPass();//不能直接用类名.实例方法会报错}
}//Student
public class Student {double score;//类方法有static通常用public修饰public static void printHelloWorld(){System.out.println(Hello World);System.out.println(Hello World);}//实例方法对象的方法public void printPass(){System.out.println(成绩((score60)?及格:不及格));}
} 补充main方法——是一个类方法 类方法的应用场景 类方法最常见的应用场景是做工具类 工具类是什么 工具类中的方法都是一些类方法每个方法都是用来完成一个功能的工具类是给开发人员共同使用的 使用类方法来设计工具类有啥好处 提高代码的复用调用方便提高开发效率 为什么工具类中的方法要用类方法而不用实例方法 · 实例方法需要创建对象来调用此时对象只是为了调用方法对象占内存这样会浪费内存 · 类方法直接用类名调用即可调用方便也节省内存 注意 工具类没有创建对象的需求建议将工具类的构造器进行私有 //muUtil 是一个工具类
public class muUtil {//将工具类的构造器进行私有private muUtil(){}public static String createCode(int n){String str ;Random r new Random();for (int i 0; i n; i) {//怎么随机生成一个随机字符、可能是数字、大写字母、小写字母//思路随机一个0-1-20表示数字、1表示大写字母、2表示小写字母int type r.nextInt(3);//可以产生0-1-2的随机数if(type 0){//0表示随机一个数字str r.nextInt(10);//0-9}else if(type 1){//1表示随机大写字母 A 65 Z 652590str (char)(r.nextInt(26)65);}else{//2表示随机小写字母 a 97 z 9725122str (char)(r.nextInt(26)97);}}return str;}
}//登录界面 4位验证码 LoginDemo
public class LoginDemo {public static void main(String[] args) {int n 4;System.out.println(登录验证码 muUtil.createCode(n));}
}//注册界面 6位验证码 RegisterDemo
public class RegisterDemo {public static void main(String[] args) {int n 6;System.out.println(注册验证码 muUtil.createCode(n));}
}
使用类方法和实例方法的注意事项 · 类方法中可以直接访问类成员不可以直接访问实例成员 · 实例方法中既可以直接访问类成员也可以直接访问实例成员 · 实例方法中可以出现this关键字类方法中不可以出现this关键字
//Student
public class Student {//类变量static String school;//实例变量double score;//类方法public static void printHello() {}//实例方法public void printIsPass() {}1.类方法可以直接访问类的成员不可以直接访问实例成员//类方法Test1public static void Test1() {//类方法可以直接访问类的成员//同一个类中访问类成员可以省略类名Student.school 清华; //school 清华Student.printHello(); //printHello2();//类方法不可以直接访问实例成员(因为实例成员属于对象)//System.out.println(score); 报错//printIsPass(); 报错//类方法中不可以出现this关键字//System.out.println(this); 报错}2.实例方法中既可以直接访问类成员也可以直接访问实例成员3.实例方法中可以出现this关键字类方法中不可以出现this关键字//实例方法Test2public void Test2(){//实例方法中既可以直接访问类成员school 北大;printHello();//实例方法也可以直接访问实例成员System.out.println(score);printIsPass();//实例方法中可以出现this关键字System.out.println(this);}
}
2.1.3 代码块* 代码块是类的五大成分之一成员变量、构造器、方法、代码块、内部类 代码块按照有无static划分为两类静态代码块、实例代码块
静态代码块 格式static {} 特点类加载时自动执行由于类只会加载一次所以静态代码块也只会执行一次 作用完成类的初始化例如对类变量的初始化赋值
实例代码块 格式{} 特点每次创建对象时执行实例代码块并在构造器前执行 作用和构造器一样都是用来完成对象的初始化例如对实例变量的初始化赋
//Student
public class Student {static int number 80;static String school;int age;//静态代码块static {System.out.println(静态代码块执行~~~);school 清华;}//实例代码块{System.out.println(实例代码块执行~~~);//age 18; //实例变量初始化赋值意义不大不可能所有人年龄一致}public Student(){System.out.println(无参数构造器执行~~~);}public Student(String name){System.out.println(有参数构造器执行~~~);}
}//demo
public class demo {public static void main(String[] args) {System.out.println(Student.number);System.out.println(Student.number);System.out.println(Student.number);System.out.println(Student.school); //清华System.out.println(--------------------);//输出结果//实例代码块执行~~~//无参数构造器执行~~~Student s1 new Student();System.out.println(--------------------);//输出结果//实例代码块执行~~~//有参数构造器执行~~~Student s2 new Student(张三);System.out.println(s1.age); //18System.out.println(s2.age); //18}
}
2.1.4 单例设计模式
设计模式一个问题有很多解法其中一种是最优的这个最优解法被人总结后称之为设计模式
设计模式有20多种对应20多种软件开发中会遇到的问题
设计模式学习思路这个设计模式解决什么问题这个设计模式怎么写
单例设计模式 确保一个类只有一个对象
单例设计模式的应用场景 任务管理器、runtime获取运行时对象……
单例设计模式的好处 可以避免浪费内存
饿汉式单例设计模式拿对象时对象早就创建好了的写法 · 把类的构造器私有 · 定义一个类变量记住类的一个对象 · 定义一个类方法放回对象
懒汉式单例设计模式拿对象时才开始创建对象的写法 · 把类的构造器私有 · 定义一个类变量用于存储对象 · 提供一个类方法保证返回的是用一个对象
//A
//饿汉式单例 频繁使用建议选择饿汉式
public class A {//2.定义一个类变量记住类的对象private static A a new A();//1.私有类的构造器private A(){}//3.定义一个类方法返回类的对象apublic static A getObject(){return a;}
}//B
//懒汉式单例
public class B {//2.定义一个类变量,用于存储这个类的一个对象private static B b;//1.私有类的构造器private B(){}//3.定义一个类方法这个方法要保证第一次调用时才创建一个对象后面调用时都会用着同一个对象返回public static B getInstance(){if(b null){b new B();}return b;}
}//demo
public class demo {public static void main(String[] args) {A a1 A.getObject();A a2 A.getObject();System.out.println(a1); //输出两个地址相同System.out.println(a2); //输出两个地址相同B b1 B.getInstance(); //第一次创建对象B b2 B.getInstance();System.out.println(b1); //输出两个地址相同System.out.println(b2); //输出两个地址相同}
}
2.2 继承 Java中提供一个关键字extends用这个关键字可以让一个类和另一个类建立起父子关系 // A称为父类基类或超类 B称为子类派生类 public class B extends A{ } 继承的特点 · 子类能够继承父类的非私有成员成员变量、成员方法 · 继承后对象的创建子类的对象是由子类、父类共同完成的
//A 父类
public class A {//公开成员public int i;public void print1(){System.out.println(print1111111);}//私有成员private int j;private void print2(){System.out.println(print2222222);}
}//B 子类
public class B extends A{private int x;public int y;//子类是可以继承父类的非私有成员public void print3(){System.out.println(i);print1();//System.out.println(j); 报错//print2(); 报错}
}//demo
public class demo {public static void main(String[] args) {B b new B();System.out.println(b.i);System.out.println(b.y);//System.out.println(b.x); 报错//System.out.println(b.j); 报错b.print1();b.print3();//b.print2(); 报错}
} 继承的好处 减少重复代码的编写 //People
public class People {private String name;public String getName() {return name;}public void setName(String name) {this.name name;}
}//Teacher
public class Teacher extends People{private String skill;public String getSkill() {return skill;}public void setSkill(String skill) {this.skill skill;}public void printInfo(){System.out.println(getName());System.out.println(getSkill());}
}//demo
public class demo {public static void main(String[] args) {Teacher t new Teacher();t.setName(张三);t.setSkill(Java python);System.out.println(t.getName());System.out.println(t.getSkill());System.out.println();t.printInfo();}
} 2.2.1 权限修饰符 权限修饰符是用来限制类中的成员成员变量、成员方法、构造器、代码块……能够被访问的范围
修饰符在本类中同一个包下的其他类里任意包下的子类里任意包下的任意类里private√缺省√√protected√√√要求继承要子类才可以访问子类对象不可以public√√√√
2.2.2 单继承 Java是单继承的Java中的类不支持多继承但是支持多层继承 2.2.3 Object类 object类是java所有类的祖宗类我们写的任何一个类其实都是object的子类或子孙类
2.2.4 方法重写 当子类觉得父类的某个方法不好用或者无法满足自己的需求时子类可以重写一个方法名称、参数列表一样的方法去覆盖父类的这个方法这就是方法重写
注意
1.重写后方法的访问Java会遵循就近原则
2.重写小技巧使用Override注解它可以指定Java编译器检查我们方法重写的格式是否正确代码可读性会更好
3.子类重写父类方法时访问权限必须大于或等于父类该方法的权限publicprotected缺省
4.重写的方法返回值类型必须与重写方法的返回值类型一样或范围更小
5.私有方法private、静态方法static不能被重写如果重写会报错的
//A
public abstract class A {protected void print1(){System.out.println(111);}public void print2(int a, int b){System.out.println(1111111);}
}//B
public class B extends A{//方法重写Override //可读性好 检查格式是否正确public void print1(){ //子类重写父类方法时访问权限必须大于或等于父类该方法的权限System.out.println(666);}Override//方法重写public void print2(int a,int b){System.out.println(6666666);}
}//demo
public class demo {public static void main(String[] args) {B b new B();b.print1();b.print2(1,2);}
}
方法重写在开发中的常见应用场景 子类重写Object类的toString()方法以便返回对象的内容
//Student
public class Student {private String name;private int age;// Override
// public String toString(){
// String str getName()今年getAge()岁;
// return str;
// }//快捷方式右键 - 生成 - toString()Overridepublic String toString() {return Student{ name name \ , age age };}public Student() {}public Student(String name, int age) {this.name name;this.age age;}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;}
}//demo
public class demo {public static void main(String[] args) {Student s1 new Student(张三,18);System.out.println(s1.toString()); //输出地址System.out.println(s1); //不加.toString()默认.toString() 输出地址}
}
2.2.5 子类访问成员的特点 在子类方法中访问其他成员成员变量、成员方法是依照就近原则的先找子类的局部范围再找子类的成员范围最后找父类的成员范围没找到则报错 如果子父类中出现了重名的成员优先子类的此时一定要使用父类的使用super关键字指定访问父类的成员super.父类成员变量/父类成员方法
2.2.6 子类构造器的特点 子类的全部构造器都会先调用父类的构造器再执行自己
子类构造器是如何实现调用父类构造器的 · 默认情况下子类全部构造器的第一行代码都是super()写不写都有它会调用父类的无参数构造器 · 如果父类没有无参数构造器 则必须在子类构造器的第一行手写super(…)指定去调用父类的有参数构造器
//父类中存在无参数构造器都不写也是默认存在
class F{public F(){System.out.println(父类的无参数构造器执行了);}
}class Z extends F{public Z(){//super(); //写不写都默认存在System.out.println(子类的无参数构造器执行了);}public Z(int a){//super(); //写不写都默认存在System.out.println(子类的有参数构造器执行了);}
}public class demo {public static void main(String[] args) {Z z new Z(); //先输出父类的无参数构造器执行了 再输出子类的无参数构造器执行了Z z2 new Z(1); //先输出父类的无参数构造器执行了 再输出子类的有参数构造器执行了}
}//父类中存在有参数构造器不存在无参数构造器子类一定要写super才能不报错
class F{public F(int m){System.out.println(父类的有参数构造器执行了);}
}class Z extends F{public Z(){super(1);System.out.println(子类的无参数构造器执行了);}public Z(int a){super(1);System.out.println(子类的有参数构造器执行了);}
}public class demo {public static void main(String[] args) {Z z new Z(); //先输出父类的有参数构造器执行了 再输出子类的无参数构造器执行了Z z2 new Z(1); //先输出父类的有参数构造器执行了 再输出子类的有参数构造器执行了}
}
子类构造器的应用场景
super(…)调用父类有参数构造器的常见应用场景是为对象中包含父类这部分的成员变量进行赋值 class Teacher extends People{private String skills;public Teacher(String name, int age, String skills) {super(name, age); //!!!!!!子类构造器调用父类构造器this.skills skills;}public String getSkills() {return skills;}public void setSkills(String skills) {this.skills skills;}
}class People{private String name;private int age;public People() {}public People(String name, int age) {this.name name;this.age age;}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 class demo {public static void main(String[] args) {Teacher t new Teacher(张三,33,Java);System.out.println(t.getName());System.out.println(t.getAge());System.out.println(t.getSkills());}
} 2.2.7 this(…)调用兄弟构造器 任意类的构造器中是可以通过this(…)去调用该类的其他构造器的 不能在一个构造器中同时写this()和super()
class Student{private String name;private int age;private String School;public Student() {}public Student(String name, int age){//this.name name;//this.age age;//this.School 无;//this(…)调用兄弟构造器可以简化代码this(name,age,无); //不能在一个构造器中同时写this()和super()}public Student(String name, int age, String school) {this.name name;this.age age;this.School school;}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 String getSchool() {return School;}public void setSchool(String school) {this.School school;}
}public class demo {public static void main(String[] args) {Student s1 new Student(张三,18,清华);//如果学生没写学校默认无Student s2 new Student(李四,18);System.out.println(s2.getName());System.out.println(s2.getAge());System.out.println(s2.getSchool());}
}
2.3 多态 多态是在继承/实现情况下的一种现象表现为对象多态、行为多态 //People 父类
public class People {public String name 父类名称;public void run(){System.out.println(人在跑步);}
}//Student
public class Student extends People{public String name 学生名称;Overridepublic void run() {System.out.println(学生在跑步);}
}//Teacher
public class Teacher extends People{public String name 老师名称;Overridepublic void run() {System.out.println(老师在跑步);}
}//demo
public class demo {public static void main(String[] args) {//对象多态People p1 new Student();People p2 new Teacher();//行为多态p1.run(); //识别技巧编译看左边父类看父类有没有该方法没有则报错运行看右边子类p2.run();System.out.println(p1.name); //父类名称 原因是变量没有多态性System.out.println(p2.name); //父类名称}
}
多态的前提 有继承/实现关系存在父类引用子类对象存在方法重写
多态的注意事项 多态是对象、行为的多态Java中的属性成员变量不谈多态
使用多态的好处 · 在多态形式下右边对象是解耦合的更便于拓展和维护 · 定义方法时使用父类类型的形参可以接收一切子类对象扩展性更强、更便利
使用多态的弊端 多态下不能直接调用子类的独有功能
多态下的类型转换问 自动类型转换父类 变量名 new 子类(); 强制类型转换子类 变量名 (子类)父类变量
强制类型转换的注意事项 · 存在继承/实现关系就可以在编译阶段进行强制类型转换编译阶段不会报错 · 运行时如果发现对象的真实类型与强制后的类型不同就会报类型转换异常ClassCastException · 强制转换前Java建议使用instanceof关键字判断当前对象的真实类型在进行强转
//People 父类
public class People {public void run(){System.out.println(人在跑步);}
}//Student
public class Student extends People{Overridepublic void run() {System.out.println(学生在跑步);}public void learn(){System.out.println(学生要学习);}
}//Teacher
public class Teacher extends People{Overridepublic void run() {System.out.println(老师在跑步);}public void teach(){System.out.println(老师要教书);}
}//demo
public class demo {public static void main(String[] args) {//好处1可以实现解耦右边对象可以随意切换Student()People p1 new Student();p1.run();//强制类型转换Student s (Student)p1;s.learn();//强制类型转换可能存在的问题编译阶段有继承或实现关系就可以强制转换但在运行时可能出现类型转换异常//Teacher t (Teacher)p1;//t.teach(); //ClassCastException类型转换异常因为Teacher类型不能指向Student()if(p1 instanceof Student){Student s2 (Student)p1;s2.learn();}else{Teacher t2 (Teacher)p1;t2.teach();}}
}
2.4 final final关键字是最终的意思可以修饰类、方法、变量 修饰类该类被称为最终类特点是不能被继承 修饰方法该方法被称为最终方法特点是不能被重写 修饰变量该变量只能被赋值一次
final修饰变量的注意事项 · final修饰基本类型的变量变量存储的数据不能被改变 · final修饰引用类型的变量变量存储的地址不能被改变但地址所指向对象的内容是可以被改变的
public class demo {
//常量用static final修饰的类变量是常量。常量建议名称全部大写多个单词下划线连接//用final修饰成员变量-类变量要直接赋值否则报错二次赋值也报错public static final String SCHOOL_NAME 清华;//public static final String SCHOOL_NAME; 报错没有直接赋值//用final修饰成员变量-实例变量要直接赋值否则报错二次赋值也报错//private final String name 张三; //用final修饰实例变量无意义导致实例变量的值无法修改//private final String name; 报错没有直接赋值public static void main(String[] args) {//final修饰变量有且只能赋值一次//变量变量包括局部变量和成员变量成员变量包括类变量和实例变量//final修饰局部变量用途1final int a;a 1;//a 2; //final修饰的变量不能二次赋值final double pai 3.14;final int[] arr {1,2,3,4};//arr null; //报错变量arr不能二次赋值变量arr存放的是数组{1,2,3,4}的地址arr[0] 5; //final修饰引用类型的变量变量存储的地址不能被改变但地址所指向对象的内容是可以被改变的//用final修饰成员变量-类变量,二次赋值报错//SCHOOL_NAME 北大; //二次赋值 报错//用final修饰成员变量-实例变量,二次赋值报错//demo d new demo();//d.name 李四; //二次赋值 报错}//final修饰局部变量用途2public static void buy(final double z){//z 1; //形参加了finalz不能被二次赋值第一次赋值是传参的时候}
}final class A{} //被final修饰后类不能被继承
//class B extends A{}class C{public final void test(){ //被final修饰后方法不能被重写System.out.println(C test);}
}class D extends C{
// Override
// public void test(){
// System.out.println(D test);
// }
}
2.4.1 常量 使用了static final修饰的成员变量就被称为常量 作用通常用于记录系统的配置信息 命名规范建议使用大写英文单词多个单词使用下划线链接起来
使用常量记录系统配置信息的优势、执行原理 · 代码可读性更好可维护性也更好 · 程序编译后常量会被“宏替换”出现常量的地方全部会被替换成其记住的字面量这样可以保证使用常量和直接用字面量的性能是一样的
public class demo {//常量static final修饰的类变量是常量。常量建议名称全部大写多个单词下划线连接public static final String SCHOOL_NAME 清华;public static void main(String[] args) {System.out.println(SCHOOL_NAME);System.out.println(SCHOOL_NAME);}
} 2.5 抽象类
什么是抽象类 在Java中有一个关键字叫abstract它就是抽象的意思可以用它修饰类、成员方法 abstract修饰类这个类就是抽象类修饰方法这个方法就是抽象方法 修饰符 abstract class 类名{ 修饰符 abstract 返回值类型 方法名称(形参列表); } public abstract class A{ public abstract void test(); } 抽象类的注意事项、特点
· 抽象类中不一定有抽象方法有抽象方法的类一定是抽象类
· 类该有的成员成员变量、方法、构造器抽象类都可以有
· 抽象类最主要的特点抽象类不能创建对象仅作为一种特殊的父类让子类继承并实现
· 一个类继承抽象类必须重写完抽象类的全部抽象方法否则这个类也必须定义成抽象类
//A 抽象类
public abstract class A {private String name;public static String schoolName;//抽象方法public abstract void run(); //抽象方法不能有方法体{}public A() {}public A(String name) {this.name name;}public String getName() {return name;}public void setName(String name) {this.name name;}public static String getSchoolName() {return schoolName;}public static void setSchoolName(String schoolName) {A.schoolName schoolName;}
}//B 子类
//一个类继承抽象类必须重写完抽象类的全部抽象方法否则这个类也必须定义成抽象类
public class B extends A{Overridepublic void run() {}
}//demo
public class demo {public static void main(String[] args) {//抽象类不能创建对象//A a new A(); 报错}
}
使用抽象类的好处 父类知道每个子类都要做某个行为但每个子类要做的情况不一样父类就把该行为定义成抽象方法交给子类去重写实现这样设计是为了更好的支持多态 //Animal
public abstract class Animal {private String name;//抽象方法public abstract void action();public Animal() {}public Animal(String name) {this.name name;}public String getName() {return name;}public void setName(String name) {this.name name;}
}//Dog
public class Dog extends Animal {public Dog() {}public Dog(String name) {super(name);}Overridepublic void action() {System.out.println(getName()汪汪汪的叫……);}
}//Cat
public class Cat extends Animal{Overridepublic void action() {System.out.println(getName()喵喵喵的叫……);}
}//demo
public class demo {public static void main(String[] args) {Animal animal1 new Dog(汪汪1号);animal1.action();Animal animal2 new Cat();animal2.setName(喵喵1号);animal2.action();}
}
抽象类的常见应用场景模板方法设计模式 模板方法设计模式解决了方法中存在重复代码的问题 模板方法设计模式的写法 1.定义一个抽象类 2.在里面定义2个方法 一个是模板方法把相同代码放里面去 一个是抽象方法具体实现子类完成 建议使用final关键字修饰模板方法 模板方法是给对象直接使用的不能被子类重写 一旦子类重写了模板方法模板方法就失效了 //Paper
public abstract class Paper {//模板方法//建议使用final关键字修饰模板方法模板方法是给对象直接使用的不能被子类重写public final void write(){System.out.println(《我的爸爸》);System.out.println(我的爸爸今年40岁了);zhengwen();System.out.println(对我而言他就是我的hero);}//抽象方法public abstract void zhengwen();
}//Student
public class Student extends Paper{Overridepublic void zhengwen() {System.out.println(他个字很高……);}
}//Teacher
public class Teacher extends Paper {Overridepublic void zhengwen() {System.out.println(他教会我骑车……);}
}//demo
public class demo {public static void main(String[] args) {//模板方法设计模式//场景学生、老师都要写一篇作文我的爸爸开头结尾都给定正文自由发挥Paper paper1 new Student();paper1.write();System.out.println();Paper paper2 new Teacher();paper2.write();}
}
2.6 接口 Java提供了一个关键字interface用这个关键字我们可以定义出一个特殊的结构接口 public interface 接口名{ //成员变量常量 // 成员方法抽象方法 } 注意接口不能创建对象接口是用来被类实现implements的是实现接口的类称为实现类 修饰符 class 实现类 implements 接口1,接口2,接口3,…{ } 一个类可以实现多个接口继承是亲爹接口是干爹实现类实现多个接口必须重写完全部接口的全部抽象方法否则实现类需要定义成抽象类
//A
public interface A {//成员变量常量//前面加不加public static final 都是常量String SCHOOL_NAME 清华;//成员方法(抽象方法)//前面加不加public abstract 都是抽象方法void testa();//接口中只能定义成员变量和成员方法不能有构造器、不能有代码块
}//B
public interface B {void testb1();void testb2();
}//C
public interface C {void testc1();void testc2();
}//D 实现类实现多个接口必须重写完全部接口的全部抽象方法
public class D implements B,C {Overridepublic void testb1() {}Overridepublic void testb2() {}Overridepublic void testc1() {}Overridepublic void testc2() {}
}//demo
public class demo {public static void main(String[] args) {System.out.println(A.SCHOOL_NAME);// A a new A(); 接口不能创建对象D d new D(); //D是实现类}
}接口的好处 弥补了类单继承的不足一个类同时可以实现多个接口 让程序可以面向接口编程这样程序员就可以灵活方便的切换各种业务实现 //demo
public class demo {public static void main(String[] args) {Student s new A();Driver d1 new A();d1.drive(); //面向接口编程Singer si new A();si.sing();Driver d2 new B(); //面向接口编程d2.drive(); //面向接口编程}
}class B implements Driver{Overridepublic void drive() {}
}//A是Student的子类也是Driver, Singer的实现类
class A extends Student implements Driver, Singer{Overridepublic void drive() {}Overridepublic void sing() {}
}class Student{}interface Driver{void drive();}interface Singer{void sing();
}
接口的综合案例 //Student
public class Student {private String name; //姓名private String sex; //性别private double score; //成绩public Student() {}public Student(String name, String 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 String getSex() {return sex;}public void setSex(String sex) {this.sex sex;}public double getScore() {return score;}public void setScore(double score) {this.score score;}
}//StudentOperator
//学生操作接口
public interface StudentOperator {public void printInfo(ArrayListStudent arr);public void printAvgScore(ArrayListStudent arr);
}//StudentOperatorImpl1
//学生操作实现类 业务方案1
public class StudentOperatorImpl1 implements StudentOperator {Overridepublic void printInfo(ArrayListStudent arr) {System.out.println(全班学生信息);System.out.println(姓名 性别 成绩);for (int i 0; i arr.size(); i) {System.out.println(arr.get(i).getName() arr.get(i).getSex() arr.get(i).getScore());}}Overridepublic void printAvgScore(ArrayListStudent arr) {double sum 0;for (int i 0; i arr.size(); i) {sum arr.get(i).getScore();}double avg sum / arr.size();System.out.println(全班学生的平均成绩是avg);}
}//StudentOperatorImpl2
//学生操作实现类 业务方案2
public class StudentOperatorImpl2 implements StudentOperator {Overridepublic void printInfo(ArrayListStudent arr) {int boy 0; //男生人数int girl 0; //女生人数System.out.println(全班学生信息);System.out.println(姓名 性别 成绩);for (int i 0; i arr.size(); i) {if(arr.get(i).getSex() 男){boy;}else if(arr.get(i).getSex() 女){girl;}System.out.println(arr.get(i).getName() arr.get(i).getSex() arr.get(i).getScore());}System.out.println();System.out.println(该班级男生boy人女生girl人);}Overridepublic void printAvgScore(ArrayListStudent arr) {double sum 0;double max arr.get(0).getScore(); //最高分double min arr.get(0).getScore(); //最低分for (int i 0; i arr.size(); i) {if(i ! 0){if(arr.get(i).getScore()max){max arr.get(i).getScore();}if(arr.get(i).getScore()min){min arr.get(i).getScore();}}sum arr.get(i).getScore();}double avg (sum-min-max) / (arr.size()-2);System.out.println(全班学生的平均成绩是avg);}
}//ClassManage 班级管理类
public class ClassManage {//如果用数组数组大小不可以变这里更应该选用集合ArrayList集合大小可变
// private Student[] s_arr new Student[4];private ArrayListStudent arr new ArrayList();//如果要切换方案1 直接把StudentOperatorImpl2()改成StudentOperatorImpl1()private StudentOperator so2 new StudentOperatorImpl2(); //面向接口编程public ClassManage() {
// s_arr[0] new Student(张三,男,99);
// s_arr[1] new Student(李四,男,89);
// s_arr[2] new Student(王五,男,59);
// s_arr[3] new Student(张三,男,99);arr.add(new Student(张三,男,70));arr.add(new Student(李四,男,89));arr.add(new Student(王五,男,59));arr.add(new Student(小美,女,99));}//打印全班学生信息public void printInfo(){
// System.out.println(全班学生信息);
// System.out.println(姓名 性别 成绩);
// for (int i 0; i arr.size(); i) {
// System.out.println(arr.get(i).getName() arr.get(i).getSex() arr.get(i).getScore());
// }so2.printInfo(arr);}//打印全班学生的平均成绩public void printAvgScore(){
// double sum 0;
// for (int i 0; i arr.size(); i) {
// sum arr.get(i).getScore();
// }
// double avg sum / arr.size();
// System.out.println(全班学生的平均成绩是avg);so2.printAvgScore(arr);}//数组版本测试
// public void method(){
// for (int i 0; i s_arr.length; i) {
// System.out.println(s_arr[i].getName() s_arr[i].getSex() s_arr[i].getScore());
// }
// }
}//demo
public class demo {public static void main(String[] args) {ClassManage cm new ClassManage();cm.printInfo();System.out.println();cm.printAvgScore();}
} 接口的细节知识JDK8开始接口中新增的三种方法 JDK8之前接口中只能有成员变量成员变量是常量和成员方法成员方法是抽象方法JDK8开始接口中新增三种方法 //A
public interface A {//新增 1.默认方法必须使用default修饰默认会被public修饰//默认方法是实例方法对象的方法因为接口不能创建对象所以必须使用实现类的对象来访问//public可省略 default void test1(){}public default void test1(){//可以带方法体System.out.println(JDK8开始接口新增);System.out.println(默认方法必须使用default修饰默认会被public修饰);System.out.println(默认方法可以带方法体);test2(); //私有方法}//新增 2.私有方法必须使用private修饰(JDK 9开始才支持)//私有方法也是实例方法对象的方法因为接是私有方法所以实现类的对象也不能访问接口内部方法可以访问private void test2(){System.out.println(JDK9开始接口新增);System.out.println(私有方法必须使用private修饰);}//新增 3.类方法静态方法必须使用static修饰//默认会被public修饰,public可省略//类方法用类名直接调用在接口里用接口名直接调用public static void test3(){System.out.println(JDK8开始接口新增);System.out.println(类方法静态方法必须使用static修饰);}
}//B
public class B implements A{
}//demo
public class demo {public static void main(String[] args) {//默认方法必须使用实现类的对象来访问B b new B();b.test1();//b.test2(); //私有方法 实现类的对象不能访问接口内部方法可以访问A.test3();}
}
接口的细节知识接口的多继承、使用接口的注意事项
接口的多继承 一个接口可以同时继承多个接口作用是便于实现类去实现 public interface C extends B,A{ } public class demo {public static void main(String[] args) {}
}interface A{void test1();
}interface B{void test2();
}//接口的多继承
interface C extends A , B{}//class D implements A , B{} 两者等同实现C相当于实现了A和B
//其实就是把AB省略直接写成C
class D implements C{Overridepublic void test1() {}Overridepublic void test2() {}
} 接口的其他注意事项
1.一个接口继承多个接口如果多个接口中存在方法签名冲突则此时不支持多继承
2.一个类实现多个接口如果多个接口中存在抽象方法签名冲突不管返回值类型是否一致方法名一致就冲突则此时不支持多实现
3.一个类继承了父类又同时实现了接口父类中和接口中有同名的默认方法实现类会优先用父类的
4.一个类实现了多个接口多个接口中存在同名的默认方法返回值类型要一致方法名也要一致可以不冲突这类重写该方法即可
//demo
public class demo {public static void main(String[] args) {Zi zi new Zi();zi.run(); //一个类继承了父类又同时实现了接口父类中和接口中有同名的默认方法实现类会优先用父类的}
}interface A{void test1(); //抽象方法
}
interface B{String test1(); //抽象方法
}
//1.一个接口继承多个接口如果多个接口中存在方法签名冲突则此时不支持多继承
//interface C extends A,B{
// 冲突
//}//2.一个类实现多个接口如果多个接口中存在抽象方法签名冲突(不管返回值一不一样方法名一样就冲突)则此时不支持多实现
//class C implements A,B{
// 冲突
//}//3.一个类继承了父类又同时实现了接口父类中和接口中有同名的默认方法实现类会优先用父类的
class Fu{public void run(){System.out.println(父类的run方法);}
}interface J{//public可省略public default void run(){System.out.println(接口的run方法);}
}class Zi extends Fu implements J{}//4.一个类实现了多个接口多个接口中存在同名的默认方法返回值类型要一致方法名也要一致可以不冲突这类重写该方法即可
interface A1{default void test1(){} //默认方法
}
interface B1{default void test1(){} //默认方法
}class D implements A1,B1{//重写方法Overridepublic void test1() {}
}
2.7 内部类 内部类是类中的五大成分之一成员变量、方法、构造器、内部类、代码块如果一个类定义在另一个类的内部这个类就是内部类 场景当一个类的内部包含一个完整的事物且这个事物没有必要单独设计时就可以把这个事物设计成内部类 public class Car{ //内部类 public class Engine{ } } 内部类有四种形式成员内部类、静态内部类、局部内部类、匿名内部类
2.7.1 成员内部类 就是类中的一个普通成员类似前面学过的普通的成员变量、成员方法 public class Outer{ //成员内部类 public class Inner{ } } 注意JDK16之前成员内部类中不能定义静态成员JDK16开始也可以定义静态成员 创建对象的格式 外部类名.内部类名 对象名 new 外部类(…).new 内部类(…); Outer.Inner in new Outer().new Inner(); //Outer
public class Outer {private int age 99;public static String a;//成员内部类public class Inner{private String name;//private static String schoolName; //JDK16开始才支持定义静态成员public int age 88;public void test(){System.out.println(age);System.out.println(a);int age 66;System.out.println(age); //66 就近原则System.out.println(this.age); //88 成员内部类Inner的成员变量age的值System.out.println(Outer.this.age); //99 指定访问外部类Outer的成员变量age的值}public Inner() {}public Inner(String name) {this.name name;}public String getName() {return name;}public void setName(String name) {this.name name;}}
}//demo
public class demo {public static void main(String[] args) {//创建成员内部类对象需要先创建外部对象Outer.Inner inner new Outer().new Inner();inner.setName(zhang);inner.test();}
}
2.7.2 静态内部类 有static修饰的内部类属于外部类自己持有 public class Outer{ //静态内部类 public static class Inner{ } } 创建对象的格式 外部类名.内部类名 对象名 new 外部类.内部类(…); Outer.Inner in new Outer.Inner(); 静态内部类中访问外部类成员的特点 可以直接访问外部类的静态成员不可以直接访问外部类的实例成员
//Outer
public class Outer {private int age;public static String a;//静态内部类public static class Inner{private String name; //普通成员变量private static String schoolName; //类变量静态成员变量public void test(){//类方法静态方法中可以直接访问类成员不可以直接访问实例成员实例成员属于对象System.out.println(a); //静态内部类可以访问外部类的类变量//System.out.println(age); //报错 静态内部类不能访问外部类的实例变量}public Inner() {}public Inner(String name) {this.name name;}public String getName() {return name;}public void setName(String name) {this.name name;}}
}//demo
public class demo {public static void main(String[] args) {//创建静态内部类对象Outer.Inner inner new Outer.Inner();inner.setName(zhang);}
}
2.7.3 局部内部类 局部内部类是定义在方法中、代码块中、构造器等执行体中 2.7.4 匿名内部类 匿名内部类就是一种特殊的局部内部类所谓匿名指的是程序员不需要为这个类声明名字 new 类或接口(参数值…){ 类体(一般是方法重写); }; 特点匿名内部类本质就是一个子类并会立即创建出一个子类对象
作用用于更方便的创建一个子类对象
//demo
public class demo {public static void main(String[] args) {
// Animal a new Cat();
// a.cry();//匿名内部类//1.把这个匿名内部类编译成子类然后会立即创建出一个子类对象来Animal a new Animal(){Overridepublic void cry() {System.out.println(喵喵喵);}};a.cry();}
}//抽象类
abstract class Animal{public abstract void cry();
}//class Cat extends Animal{
// Override
// public void cry() {
// System.out.println(喵喵喵);
// }
//}
匿名内部类在开发中的使用场景 通常作为一个参数传输给方法
//demo
public class demo {public static void main(String[] args) {
// Swimming s1 new Swimming(){
// Override
// public void swim() {
// System.out.println(小狗游泳);
// }
// };
// go(s1);go(new Swimming(){Overridepublic void swim() {System.out.println(小狗游泳);}});Swimming s2 new Swimming(){Overridepublic void swim() {System.out.println(小猫游泳);}};go(s2);}//设计一个方法可以接收swimming接口的一切实现类对象进来参加游泳比赛public static void go(Swimming s){System.out.println(开始——————————————————);s.swim();}}//猫和狗都要参加游泳比赛
interface Swimming{void swim();
}
匿名内部类不是自己主动去用是别人需要让我们用的时候用别人需要的对象是接口类型用匿名内部类 或写实现类
//demo
public class demo {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(400,400); //窗口大小win.setLocationRelativeTo(null); //窗口居中win.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); //关闭窗口退出程序win.setVisible(true); //可见}
}
2.8 枚举 枚举是一种特殊类 枚举类的格式 修饰符 enum 枚举类名{ 名称1,名称2,…; 其他成员… } 注意 · 枚举类中的第一行只能写一些合法的标识符名称多个名称用逗号隔开 · 这些名称本质是常量每个常量都会记住枚举类的一个对象 //A
public enum A {//注意枚举类的第一行必须罗列的是枚举对象的名字X, Y, Z;private String name;public String getName() {return name;}public void setName(String name) {this.name name;}
}//B
//抽象枚举
public enum B {//枚举类中的第一行只能写一些合法的标识符名称这些名称本质是常量每个常量都会记住枚举类的一个对象//因为枚举类中有抽象方法所以这个枚举类是抽象枚举类因此一个类继承抽象类必须重写完抽象类的全部抽象方法X(){ //相当于创建了一个B枚举对象Overridepublic void go(){}},Y(张三){ //相当于创建了一个B枚举对象Overridepublic void go(){System.out.println(getName());}};private String name;//private可省略默认私有private B() {}//private可省略默认私有private B(String name) {this.name name;}public abstract void go();public String getName() {return name;}public void setName(String name) {this.name name;}
}//demo
public class demo {public static void main(String[] args) {A a1 A.X;System.out.println(a1);//枚举类的构造器是私有的不能对外创建对象//A a new A();//枚举类的第一行都是常量记住的是枚举类的对象A a2 A.Y;//枚举类提供一些额外的APIA[] all A.values(); //拿到全部对象A a3 A.valueOf(Z);System.out.println(a3.name()); //拿到a3的名字System.out.println(a3.ordinal()); //拿到a3的索引B b1 B.Y;b1.go();}
}
用枚举类写单例设计模式
public enum C {X; //单例
}枚举的常见应用场景 用来表示一组信息然后作为参数进行传输
选择定义一个一个的常量来表示一组信息并作为参数传输 · 参数值不受约束
选择定义枚举表示一组信息并作为参数传输 · 代码可读性好参数值得到了约束对使用者更友好建议
// Constant2
public enum Constant2 {BOY,GRIL;
}//demo
public class demo {public static void main(String[] args) {//拿枚举类做信息标志和分类check(Constant2.BOY);}public static void check(Constant2 sex){switch (sex){case BOY:System.out.println(男生关注的信息);break;case GRIL:System.out.println(女生关注的信息);break;}}
}2.9 泛型 定义类、接口、方法时同时声明了一个或者多个类型变量如E称为泛型类、泛型接口、泛型方法它们统称为泛型 public class ArrayListE{ …… } 作用泛型提供了在编译阶段约束所能操作的数据类型并自动进行检查的能力这样可以避免强制类型转换及其可能出现的异常
泛型的本质把具体的数据类型作为参数传给类型变量
//demo
public class demo {public static void main(String[] args) {//没有定义泛型默认时object类型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 s (String) list.get(i);System.out.println(s);}System.out.println();//ArrayListString list1 new ArrayListString();ArrayListString list1 new ArrayList(); //JDK1.7开始后面中可以不写类型list1.add(java1);list1.add(java2);list1.add(java3);//list1.add(new Cat()); 报错泛型可以在编译阶段约束能够操作的数据类型for (int i 0; i list.size(); i) {String s list1.get(i);System.out.println(s);}}
}
2.9.1 泛型类 自定义泛型类 修饰符 class 类名类型变量,类型变量,……{ } //demo
public class demo {public static void main(String[] args) {MyArrayListString list new MyArrayList();list.add(java1);list.add(java2);//list.add(java3);System.out.println(list.get(6));//泛型可以声明多个类型变量MyClassString,String c new MyClass();//是它本身或者它的子类MyClass2Dog m1 new MyClass2();MyClass2Animal m2 new MyClass2();}
}//MyArrayList
public class MyArrayListE {private Object[] o_arr new Object[2];private int size0;public boolean add(E e){if(sizeo_arr.length){o_arr[size] e;size;return true;}else{System.out.println(超出数组长度);return false;}}public E get(int index){if(indexo_arr.length){return (E)o_arr[index];}else{return (E)您访问的索引越界;}}
}//MyClass(泛型可以声明多个类型变量)
public class MyClassE,T {public void put(E e,T t){}
}//MyClass2 //是它本身或者它的子类
public class MyClass2E extends Animal {
}//Animal
public class Animal {
}//public class Dog extends Animal {
}
2.9.2 泛型接口 修饰符 interface 接口名类型变量,类型变量,……{ } //demo
public class demo {public static void main(String[] args) {//系统需要处理学生和老师的数据//两个功能保存对象数据根据名称查询数据Teacher t new Teacher(张三,男,Java);TeacherData t1 new TeacherData();t1.add(t);t1.find(张三);t1.find(李四);}
}//People
public class People {private String name; //姓名private String sex; //性别public People() {}public People(String name, String sex) {this.name name;this.sex sex;}public String getName() {return name;}public void setName(String name) {this.name name;}public String getSex() {return sex;}public void setSex(String sex) {this.sex sex;}
}//Teacher
public class Teacher extends People{private String teach; //学科public Teacher(){}public Teacher(String teach) {this.teach teach;}public Teacher(String name, String sex, String teach) {super(name, sex);this.teach teach;}public String getTeach() {return teach;}public void setTeach(String teach) {this.teach teach;}
}//Student
public class Student extends People{private int classroom; //班级public Student(){}public Student(int classroom) {this.classroom classroom;}public Student(String name, String sex, int classroom) {super(name, sex);this.classroom classroom;}public int getClassroom() {return classroom;}public void setClassroom(int classroom) {this.classroom classroom;}
}//Data
//泛型接口
public interface DataE {void add(E e); //即需要保存学生数据也需要保存老师数据使用泛型比较好ArrayListE find(String name);
}//TeacherData
public class TeacherData implements DataTeacher {private ArrayListTeacher arr_s new ArrayList(); //保存老师数据的集合Overridepublic void add(Teacher teacher) {arr_s.add(teacher);}Overridepublic ArrayListTeacher find(String name) {for (int i 0; i arr_s.size(); i) {if(arr_s.get(i).getName() name){ //找到名字一样的System.out.println(查询成功);System.out.println(arr_s.get(i).getName() arr_s.get(i).getSex() arr_s.get(i).getTeach());}else{System.out.println(查询失败老师列表中没有此人);}}return null; //返回ArrayListTeacher感觉不太对查询信息返回整个集合 应该返回学生对象即可}
}//StudentData
public class StudentData implements DataStudent {private ArrayListStudent arr_s new ArrayList(); //保存学生数据的集合Overridepublic void add(Student student) {arr_s.add(student);}Overridepublic ArrayListStudent find(String name) {return null;}
}
2.9.3 泛型方法 修饰符类型变量,类型变量,……返回值类型 方法名(形参列表){ } 通配符 就是 可以在使用泛型的时候代表一切类型E T K V等字符是在定义泛型的时候使用
泛型的上下限 泛型上限extends Car能接收的必须是Car或者它的子类 泛型下限super Car能接收的必须是Car或者它的父类
//demo
public class demo {public static void main(String[] args) {String s method(Java);System.out.println(s);Dog d method(new Dog());System.out.println(d);//需求所有汽车参加比赛ArrayListCar cars new ArrayList();cars.add(new BENZ());cars.add(new BNW());go(cars);ArrayListBNW bnws new ArrayList();bnws.add(new BNW());bnws.add(new BNW());//go(bnws);//报错 因为go的形参需要ArrayListCar所以ArrayListBNW不行//虽然Car是BNW的父类但是ArrayListBNW和ArrayListCar无关//public static void go(ArrayListCar cars)//如果想要把ArrayListBNW可以使用需要把go方法加上泛型go(bnws);}// public static void go(ArrayListCar cars){
//
// }// public static T extends Car void go(ArrayListT cars) {
// //不加extends Car任何ArrayListXX都能加进来
// }// 通配符 在使用泛型的时候可以代表一切类型 ? extends Car上限 Car和Car的子类能进来 ? super Car下限 Car和Car的父类能进来public static void go(ArrayList? extends Car cars) {//不加extends Car任何ArrayListXX都能加进来}//泛型方法public static T T method(T t){return t;}
}//Car
public class Car {
}//BENZ
public class BENZ extends Car{
}//BNW
public class BNW extends Car{
}//Dog
public class Dog {
}
泛型的擦除问题和注意事项 · 泛型是工作在编译阶段的一旦程序编译成class文件class文件中就不存在泛型了这就是泛型擦除 · 泛型不支持基本数据类型int、double等只能支持对象类型引用数据类型