文章目录
类
概述
定义:
是对现实生活中一类具有相同属性和行为的事物的抽象。
特点:
①类是对象的数据类型
②类是具有相同属性和行为的一组对象的集合
③一个类可以对应多个对象,只要对象的属性和行为是相同的
类基础内容
类的重要性
是java程序的基本组成单位;
类
是对现实生活中一类具有相同属性和行为的事物的抽象,确定对象将拥有的属性和行为。
类的组成
属性和行为。
属性:在类中通过成员变量来体现(类中方法外的变量)
行为:在类中通过成员方法来体现(和前面的方法相比去掉static关键词即可)
类相关内容
所有类的基类:java.lang.Object类。
main()函数的合法参数:String args[] 。
类的定义步骤
定义步骤:
①定义类
②编写类的成员变量
③编写类的成员方法
//①定义类
public class 类名(){
//②编写类的成员变量
变量1数据类型 变量1;
变量2数据类型 变量2;
//③编写类的成员方法,定义方法去掉static关键字
方法1;
方法2;
}
案例:
// 说明:
类手机;
成员变量品牌、价格;
成员方法打电话、发短信;
// Demo110
public class Demo110 {
//编写类的成员变量
String brand;
int price;
//成员方法
public void call(){
System.out.println("打电话");
}
public void sendMessage(){
System.out.println("发短信");
}
}
标准类制作
制作要求:
- 成员变量
使用private修饰 - 构造方法
提供一个无参构造方法
提供一个带多个参数的构造方法 - 成员方法
提供每一个成员变量对应的setXxx()/getXxx()
提供一个显示对象信息的show() - 创建对象并为其成员变量赋值的两种方式
无参构造方法创建对象后使用setXxx()赋值 ——》无参数构造方法 + setXxx()方法
使用带参数构造方法直接创建带有属性值的对象 ——》有参数构造方法
案例
// 111
//标准类制作
public class Student1 {
//定义private修饰的成员变量
private String name;
private int age;
//定义无参数和有参数的构造方法
public Student1(){
}
public Student1(String name,int age){
this.name = name;//this.name 表示的是类的成员变量 name表示的是局部变量
this.age = age;
}
//提供给每一个成员变量对应的get/set方法
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 void show(){
System.out.println(name+","+age);
}
}
//测试类
public class StudentDemo1 {
public static void main(String[] args){
//使用无参数构造方法创建对象,使用setXxx()方法实现对成员变量的赋值
Student1 stu1 = new Student1();
stu1.setName("汪苏泷");
stu1.setAge(33);
stu1.show();//汪苏泷,33
//使用带参数的构造方法创建对象并通过参数赋值
Student1 stu2 = new Student1("许嵩",36);
stu2.show();//许嵩,36
}
}
内部类
概述
概念:
就是在一个类中定义一个类。
格式:
public class 类名{
修饰符 class 类名{
}
}
内部类修饰符 一般是private
特点:
①内部类可以直接访问外部类的成员,包括私有
public class Outer {
//内部类可以访问外部类的成员
private int age = 20;
//内部类 Inter
public class Inter{
public void show(){
System.out.println(age);
}
}
}
②外部类要访问内部类的成员,必须创建对象
// 外部类 Outer
public class Outer {
//内部类可以访问外部类的成员
private int age = 20;
//内部类 Inter
public class Inter{
public void show(){
System.out.println(age);
}
}
public void method(){
//外部类访问内部类的成员,必须创建内部类的方法
// show();//直接访问会报错
Inter i = new Inter();
i.show();
}
}
内部类分类:
根据内部类在类中定义的位置不同:
①在类的成员位置:成员内部类
②在类的局部位置:局部内部类
成员内部类
格式
public class Outer {
private int num = 20;
//Inter就是Outer类的成员内部类
public class Inter{
public void show(){
System.out.println(num);
}
}
}
访问
- 内部类修饰符public
成员内部类,外界创建对象访问
格式:
外部类名.内部类名 对象名 = 外部类对象.内部类对象;
例子:Outer.Inter oi = new Outer().new Inter();
理解xhj:
出现内部类的原因是:把内部类的内容隐藏起来,不想让外界直接看到/访问。
则一般内部类定义 修饰符的位置private而不是public。
- 内部类修饰符private
内部类修饰符是private时,访问内部类的方法。
在外部类中 创建成员方法:创建内部类对象,通过对象调用方法实现访问;
在测试类中 创建外部类的对象,通过对象调用外部类成员方法的形式实现对内部类方法的访问。
public class Outer {
private int num = 20;
//Inter就是Outer类的成员内部类
// 成员内部类 public修饰
public class Inter{
public void show(){
System.out.println(num);
}
}
// 成员内部类 private修饰
private class Inter{
public void show(){
System.out.println(num);
}
}
// 成员方法
public void method(){
Inter i = new Inter();
i.show();
}
}
public class OuterDemo {
public static void main(String[] args) {
//内部类 采用修饰符public,可以采用下面方式访问内部类中的方法
//成员内部类 public修饰 访问类的方法
/* Outer.Inter oi = new Outer().new Inter();
oi.show();*/
//内部类 采用修饰符private,采用下述形式访问内部类方法。
// 在外部类中写成员方法,方法中 创建内部类对象,通过对象.方法实现对内部类的访问。
Outer o = new Outer();
o.method();//20
}
}
局部内部类
格式
位置是:在外部类成员方法中。
public class Outer {
private int num = 10;
public void method(){
class Inter{
public void show(){
System.out.println(num);
}
}
}
}
访问
特点①
局部内部类是在方法中定义的类,所以外部是无法直接使用,需要在方法内部创建对象并使用。
特点②
该类可以直接访问外部类的成员变量,也可以访问方法内的局部变量。
public class Outer {
//外部类的成员变量
private int num = 10;
public void method(){
//外部类成员方法内的局部变量
int num2 = 30;
class Inter{
public void show(){
System.out.println(num);//10
System.out.println(num2);//20
}
}
Inter i = new Inter();
i.show();
//创建外部类成员,不在内部类中创建对象、调用show方法,外部类创建的对象将不能访问局部内部类的show方法
}
}
public class OuterDemo {
public static void main(String[] args) {
Outer o = new Outer();
o.method();
}
}
分析
外部类的成员方法method
①method方法中只有局部内部类 Inter
则对象.method→什么也不执行。
②method方法中有局部内部类Inter;Inter类的实例化对象;对象.show方法,输出外部类的成员变量;
外部类对象.method→结果是外部类的成员变量num = 10
③method方法中有局部内部内Inter;Inter类的实例化对象;对象.show方法,输出外部类的成员变量、method方法的局部变量;
对象.method→结果是外部类的成员变量num = 10、外部类成员方法的局部变量 num2 = 30
匿名内部类
概述
匿名内部类 = 是局部内部类的一种。
前提: 存在一个类或者接口,类可以是具体类或抽象类
格式:
new 类名或者接口名(){
重写方法;
};
理解:
①new 类名或者接口名() ;
说明整体是一个对象,只不过对象没有名字,也称为匿名对象,即匿名类本质是一个匿名对象。
②重写方法,
说明它继承了前面的类 或者 实现了前面的接口。
本质:
是一个继承了该类或者实现了该接口的子类匿名对象。
案例 接口实现类的匿名内部类
// 接口
public interface Inter {
//接口 = 抽象内容
// 抽象方法
public abstract void show();
}
//测试类
public class OuterDemo {
public static void main(String[] args) {
Outer o = new Outer();
o.method();
}
}
public class Outer {
//匿名内部类是局部内部类的一种,所以需要在外部类的方法中书写
public void method(){
//匿名内部类的前提是 存在一个类或接口 所以需要先定义类或者接口 本案例中定义一个接口
new Inter(){
@Override
public void show() {
System.out.println("匿名内部类的show方法");
}
};
//此时method方法中有 内容了,执行测试类 但是没有输出结果
}
想要多次调用匿名内部类的方法,多次重写匿名内部类并进行调用即可。
public class Outer {
//匿名内部类是局部内部类的一种,所以需要在外部类的方法中书写
public void method(){
//要想实现匿名内部类方法的调用,匿名内部类的本质是 继承了类或接口的对象,所以可以直接匿名内部类.方法进行方法的调用。
new Inter(){
@Override
public void show() {
System.out.println("匿名内部类的show方法");
}
}.show();
new Inter(){
@Override
public void show() {
System.out.println("匿名内部类的show方法");
}
}.show();
}
public class Outer {
//匿名内部类是局部内部类的一种,所以需要在外部类的方法中书写
public void method(){
//但如果多次调用,则一直重复会造成代码复用性差,
//new 是Inter(),并且又重写了show方法,则new Inter(){}整体可以认为是 接口Inter的实现类对象 那么可以按照多态的形式 将其赋值给Inter类接口。
Inter i = new Inter(){
@Override
public void show() {
System.out.println("匿名内部类的show方法");
}
};
i.show();
}
}
匿名内部类在开发中的使用
分析:
创建操作类对象,调用method方法
method方法 参数是接口名时,说明需要的是 接口实现类的对象
public class JumppingOperator {
//接口的操作类
public void method(Jumpping j){
//参数是接口名,说明需要的是 接口的实现类对象
j.jump();
}
}
这时 可以采用匿名内部类的形式,
new 类名/接口名(){
@Override
重写方法;
};
匿名内部类的本质是:继承类或实现接口类的对象。
// 创建 JumppingOperator操作类 的 对象
JumppingOperator j = new JumppingOperator();
j.method(new Jumpping() {
@Override
public void jump() {
System.out.println("猫可以跳高了");
}
});
完整:
public interface Jumpping {
//接口是抽象的内容,接口中定义方法修饰符不写 默认是public abstract
void jump();
}
public class JumppingOperator {
//接口的操作类
public void method(Jumpping j){
//参数是接口名,说明需要的是 接口的实现类对象
j.jump();
}
}
// 测试类
public class JumppingDemo {
public static void main(String[] args) {
// 创建操作类对象,调用method方法
// method方法 参数是接口名时,说明需要的是 接口实现类的对象
// 这时 可以采用匿名内部类的形式,new 类名/接口名(){重写方法;}; 匿名内部类的本质是:继承类或实现接口的对象。
JumppingOperator j = new JumppingOperator();
Jumpping jj = new Cat();
j.method(jj);//方法需要的 Jumpping接口的实现类对象
System.out.println("--------------");
//如果多次创建 Jumpping接口的 不同实现类 这样会产生多个类文件,只是用一次,会造成文件冗余。采用匿名内部类实现。
j.method(new Jumpping() {
@Override
public void jump() {
System.out.println("猫可以跳高了");
}
});
//其本质需要是的Jumpping接口实现类的对象,使用匿名内部类的形式,不用额外创建Jumpping的实现类。
}
}
抽象类
概述
概念:
java中一个没有方法体的方法应该定义为抽象方法,而类中如果有抽象方法,该类必须定义为抽象类。
public abstract class Animal{
public abstract void eat();
}
理解xhj:
①抽象类出现的原因:
创建父类的时候,通过多态形式(父类-子类)创建对象一般都是特殊的对象,且重写的内容都不一样;假设子类没有重写父类的方法,那么不同子类调用方法输出结果是都一样的,这显然和实际不符;所以要重写的方法不能由方法体,就需要被abstract修饰,定义为抽象方法;
②如果一个类中的方法需要定义为抽象方法,也就是被abstract修饰,那么它所在的类也需要被abstract修饰。
抽象类的特点
①抽象类和抽象方法必须使用abstract关键字修饰
public abstract class 类名{}
public abstract void 方法名();
② 抽象类中不一定有抽象方法,有抽象方法的类一定是抽象类
理解:抽象类中 可以只有一般的成员方法,没有抽象方法
③ 抽象类不能实例化,参照多态的方式,通过子类对象实例化,这叫抽象类多态。
父类 对象名 = new 子类();
④抽象类的子类 会报错
解决方式:
①重写抽象类中的所有抽象方法;
②定义为抽象类;
理解:
①抽象类不能实例化,指的是不能直接实例化,但可以通过多态的方式进行实例化。
直接实例化(抽象类xxx ):xxx 对象名 = new xxx();
②抽象类中有构造方法,作用是:当抽象类通过多态实例化对象时,用于子类访问父类数据的初始化,即子类的构造方法会访问父类的构造方法,用于对子类所需父类数据的初始化。
备注2022/8/11
抽象方法的方法体必须被一对大括号包住;
抽象类的成员特点
① 成员变量
可以是变量,也可以是常量
final修饰的成员变量 不能被修改,即为常量。
private int age = 20; //变量
private final String cityContext = "北京";//常量
② 构造方法
有构造方法(无参、有参),但是不能直接实例化
作用:用于子类访问父类数据的初始化
构造方法:用于子类访问父类构造方法完成对它数据的初始化
public Animal(){ }
public Animal(int age){
this.age = age;
}
直接实例化:
类名xxx 对象名 = new 类名xxx();
③ 成员方法
抽象方法:限定子类必须完成某些动作,即限定子类必须重写父类的某些方法
非抽象方法:提高代码复用性,由继承保证的。
非抽象两方法:
public void show(){
age = 40;
System.out.println(age);
System.out.println(cityContext);
}
抽象方法:
public abstract void eat();
案例:猫和狗(抽象类版本)
// 127-test2
// 定义抽象类 以及 抽象方法 此是父类
public abstract class Animal {
private String name;
private int age;
public Animal(){}
public Animal(String name,int age){
this.name = name;
this.age = age;
}
public abstract void eat();
public void setName(String name){
this.name = name;
}
public String getName(){
return name;
}
public void setAge(int age){
this.age = age;
}
public int getAge() {
return age;
}
}
public class Cat extends Animal {
@Override
public void eat() {
System.out.println("猫吃鱼");
}
public Cat(){}
//子类创建有参构造方法,需要使用父类中的变量,必须使用父类的有参构造方法实现。super(参数1,参数2);
public Cat(String name,int age){
super(name,age);
}
}
public class Dog extends Animal {
@Override
public void eat() {
System.out.println("狗吃骨头");
}
public Dog(){}
public Dog(String name,int age){
super(name,age);
}
}
public class AnimalDemo {
public static void main(String[] args){
Animal ao = new Cat();
ao.setName("加菲");
ao.setAge(5);
System.out.println(ao.getName() + ", " + ao.getAge());//加菲, 5
ao.eat();//猫吃鱼
ao = new Dog("贵宾",2);
System.out.println(ao.getName() + ", "+ao.getAge());//贵宾, 2
ao.eat();//狗吃骨头
}
}
抽象类和普通类的区别
区别 | 抽象类 | 普通类 |
---|---|---|
实例化 | 为了被继承,不能实例化 | 可以实例化一个对象 |
重写 | 必须重写抽象类中的抽象方法 | 可以选择重写父类方法、也可以直接调用父类方法 |
修饰符 | 必须用abstract修饰 | 不使用 |
相同点
普通类和抽象类都可以含有普通成员属性和普通方法;
普通类和抽象类都可以继承别的类或者被别的类继承;
普通类和抽象类的属性和方法都可以通过子类对象来调用;
基本类型包装类
概述
- 基本类型包装类 = 基本数据类型封装成的对象;
- 将基本数据类型封装成对象的好处:可以在对象中定义更多的功能方法操作该数据;
- 常见的操作之一:用于基本数据类型与字符串之间的转换;
基本数据类型与对应的包装类
基本数据类型 | 包装类 |
---|---|
byte | Byte |
short | Short |
int | Integer |
long | Long |
float | Float |
double | Double |
char | Character |
boolean | Boolean |
integer类
概念
- 软件包是 java.lang 使用时不需要导包
- integer类 间接 继承于 Number、Object
- public final class Integer 说明Integer是最终类,不能被继承,也就是不能有子类
- 包装一个对象中的原始类型int的值
常用方法
方法名 | 说明 |
---|---|
public Integer(int value) | 根据jint值创建Integer对象(过时) |
public Integer(String s) | 根据String值创建Integer对象(过时)(这里的字符串只能是数组的不能是字符的) |
public static Integer valueOf(int i) | 返回表示指定的int值的Integer实例 |
public static Integer valueOf(String s) | 返回一个保存指定String值的Integer对象 |
public int intValue() | 返回Integer的值作为int Integer对象.intValue() |
static int parseInt(String s ) | 将字符串参数解析为带符号的十进制整数 |
案例:
// 130-test5
public class IntegerDEmo {
public static void main(String[] args) {
System.out.println("过时方式-----------");
//通过构造方法,根据参数 创建Integer对象。
Integer i = new Integer(100);
System.out.println(i);
Integer i2 = new Integer("100");
System.out.println(i2);
Integer i3 = new Integer("abc");
// System.out.println(i3);//NumberFormatException
//这里会报错
System.out.println("推荐方式--------------");
Integer i4 = Integer.valueOf(100);
System.out.println(i4);
Integer i5 = Integer.valueOf("563");
System.out.println(i5);
Integer i6 = Integer.valueOf("abc");
System.out.println(i6);//NumberFormatException
}
}
注意
- 当使用Integer ii = Integer.valueof(String s)的时候,s参数只能是数字类型的字符串,也就是“12233”这种类型,否则会报错NumberFormatException
int和String的相互转换
int—String
①
String s = “” + int类型变量
②
public static String valueOf(int i)
返回int参数的字符串表示形式,该方法是String类中方法。
案例:
//int ---String
int number = 100;
//方式1:通过字符串加的形式
String s1 = "" + number;
System.out.println(s1);//100
//方式2:public static String valueOf(int i)
String s2 = String.valueOf(100);
System.out.println(s2);//100
String — int
① String—Integer—int
String => Integer
Integer i = Integer.valueOf(字符串);
Integer => int
int x = i.intValue();
Integer基本类型包装类的对象.intValue() --》 把Integer类的对象转成int类型。
② String – int
Integer.parseInt(String s)
public static int parseInt(String s)
将字符串解析为int类型,该方法是Integer类中的方法。
案例:
//String -- int
String s = "100";
// 方式1:String-Integer-int
Integer i = Integer.valueOf(s);
//public int intValue() Integer类中的方法
int x = i.intValue();
System.out.println(x);//100
//方式2:String -- int
//public static int parseInt(String s)
int y = Integer.parseInt(s);
System.out.println(y);//100
案例:字符串中数据排序
需求:
有一个字符串,“91 27 46 38 50” 请写程序实现最终输出结果是“27 38 46 50 91”
关键点: 字符串–字符串数组–int类型数组–数据元素排序–字符串
分析理解:
1 定义一个字符串
2 得到字符串中的数字 组成一个数字数组 使用方法public String[] split(String regex)
通过【字符串.split(regex:“分隔符”)】
3 把字符串数组中的每一个元素存储在int数组中
通过for循环,实现遍历字符串数组中的每一个元素;
方法public static int parseInt(String s):将字符串转为int类型。是Integer基础类型包装类中的;
形式:int i = Integer.parseInt(String s)
4 对int数组进行排序
使用方法Arrays.sort(数组名);
5 排序后的数组组成一个字符串
使用StringBuilder类的对象中的方法append()方法。
创建StringBuilder对象,使用对象.append(),然后再使用对象.toString()转为String类型。
// 131-test1
public class Deno1 {
public static void main(String[] args) {
//定义一个字符串
String s1 = "91 27 46 38 50";
//把字符串中的数字数据存储到一个int类型的数组中
//得到字符串中的每一个数字数组public String[] split(String regex)
//此方法需要通过字符串.split调用
String[] arrStr = s1.split(" ");
/* for(int i = 0; i<arrStr.length ; i++){
System.out.println(arrStr[i]);
}*/
//定义一个int数组,把String数组中的每一个元素存储到int数组中
//public static int parseInt(String s)是Integer基础类型包装类中的
int[] arr = new int[arrStr.length];
for (int i = 0; i <arrStr.length; i++){
arr[i] = Integer.parseInt(arrStr[i]);
}
//对int数组进行排序
Arrays.sort(arr);
//对排序后的int数组中的元素进行拼接得到一个字符串,这里的拼接采用StringBuilder实现
StringBuilder sb = new StringBuilder();
for (int i = 0; i<arr.length; i++){
if(i == arrStr.length - 1){
sb.append(arr[i]);
}else{
sb.append(arr[i]).append(" ");
}
}
String s2 = sb.toString();
//输出结果
System.out.println(s2);
}
}
自动装箱和拆箱
概念:
- 装箱:把基本数据类型转换为对应的包装类类型
手动装箱:
Integer i = Integer.valueOf(100);
自动装箱:
Integer ii = 100;
- 拆箱:把包装类类型转换为对应的基本数据类型
手动拆箱:
ii = ii.intValue() + 100;
表示:手动拆箱 和 自动装箱
ii.intValue() 手动拆箱,
Integer = int + int 自动装箱
自动拆箱:
ii += 200;
表示自动拆箱和自动装箱;
ii+200 Integer + 200 自动拆箱
ii = ii + 200 Integer = int 自动装箱
理解xhj:
Ingeter iii = null;
iii += 300;
//此时会报错NullPointerException
注意:
①在使用包装类类型的时候,如果做操作,最好先判断是否为null
②只要是对象,在使用前就必须进行不为null的判断;
接口
概述
接口用于描述系统对外提供的所有服务,因此接口中的所有成员常量和方法都必须是public类型;
java中的接口更多体现的是对行为的抽象。
接口(interface)和类(class)是并列的结构。
接口特点
- 接口用关键字interface 修饰
public [abstract] interface 接口名{}
- 类实现接口用implements表示
public class 类名 implements 接口名{}
备注2022/8/11
java接口的修饰符可以为public abstract
-
接口不能直接实例化
直接实例化(接口名 对象 = new 接口名{})
需要:参照多态方式,通过实现类对象进行实例化,这叫接口多态。 -
接口的实现方式两种
①重写接口中的所有抽象方法;
②接口的实现类是抽象类;
理解xhj:
①接口是抽象内容,所以接口中可以有抽象方法;
案例:
// 127-test3
// 定义一个接口
// 接口是一个抽象内容,所以接口中可以有抽象方法。
public interface Jumpping {
// 接口中可以定义抽象方法
public abstract void jump();
}
// 类和接口的关系是 类实现接口 = 类名 implements 接口名
public class Cat implements Jumpping {
// Cat报错 因为:没有重写接口Jumpping中的抽象方法
@Override
public void jump() {
System.out.println("猫可以跳高了");
}
}
public abstract class Dog implements Jumpping {
//类实现接口 报错
// 解决方式:①重写接口中的抽象方法②将类定义为抽象类,但是后续继承此类的子类还是需要重写抽象方法的。
}
public class JuppingDemo {
public static void main(String[] args) {
//接口的实例化
// Jumpping j = new Jumpping();
//接口是抽象内容,不能直接进行实例化,可以通过多态实现实例化
Jumpping j = new Cat();
j.jump();
}
}
接口的成员特点
成员变量
- 只能是常量,默认修饰符:public static final
构造方法
- 接口没有构造方法,因为接口主要是对行为进行抽象的,没有具体存在
- 一个类如果没有父类,默认继承自Object类
- 接口实现类的构造方法 需要调用接口的构造方法,但接口没有,调用的是Object类的构造方法。
//定义接口的实现类
public class InterImpl implements Inter {
//接口类的定义实际上等价于
//public class InterImpl extends Object implements Inter{
public InterImpl(){
// 接口实现类的构造方法 会自动调用接口的无参构造方法,但接口又没有无参构造方法,它调用的是Object类的无参构造方法
super();
}
}
成员方法
- JDK7.0之前 :只能是抽象方法,默认修饰符:public abstract
- JDK7.0之后:可以有抽象方法、静态方法、默认方法。
理解xhj:
- 类Object是类层次结构的根,每个类都有Object作为超类(父类、基类),所有对象(包括数组)都实现了这个类的方法。
- 接口实现类的构造方法 会自动调用 接口的无参构造方法,但接口又没有无参构造方法,它调用的是Object类的无参构造方法。
案例:猫和狗
需求:采用抽象类和接口来实现猫狗案例,并在测试类中进行测试。
注意xhj:
抽象类:
通过子类继承抽象类实例化的对象,只能调用抽象类中的抽象方法
接口:
通过接口实现类实例化的对象,只能调用接口中的抽象方法
备注2022/8/11
多态形式创建对象:编译看左边、执行看右边。
一个类 = 抽象类的子类、接口的实现类
public class 子类 extends 抽象类 implements 接口{}
// 127-test5
// 创建接口
public interface Jumpping {
public abstract void jump();
}
// 抽象类
public abstract class Animal {
private String name;
private int age;
public Animal(String name, int age) {
this.name = name;
this.age = age;
}
public Animal() {
}
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 abstract void eat();
}
// 接口实现类
public class Cat extends Animal implements Jumpping{
public Cat(){}
public Cat(String name,int age){
super(name,age);
}
@Override
public void eat() {
System.out.println("猫吃鱼");
}
@Override
public void jump() {
System.out.println("猫可以跳高了");
}
}
// 测试
public class JumppingDemo {
public static void main(String[] args) {
// 接口多态创建对象
Jumpping j = new Cat();
j.jump();
// j.eat();//报错
// 采用多态的形式创建对象,成员方法的调用 编译要看等号左侧,执行要看等号右侧
// 编译期间,左侧的Jumpping接口并没有eat抽象方法,所以编译会报错。
System.out.println("-----------");
// 抽象类多态创建对象
Animal ao = new Cat();
ao.setName("加菲");
ao.setAge(2);
System.out.println(ao.getName() + ", " + ao.getAge());
ao.eat();
// ao.jumpping();//报错。
//通过抽象类实例化的对象,只能调用抽象类中的抽象方法
//通过接口实例化的对象,只能调用接口中的抽象方法
}
}
类和接口的关系
①类和类的关系
继承关系,只能单继承,但是可以多层继承
public class Granddad{}
public class Dad extends Granddad{}
public class Son extends Dad{}
多层继承,Son类也继承了Granddad、Dad中的内容。
②类和接口的关系
实现关系:可以单实现,也可以多实现;一个类同时实现多个接口
继承关系:可以继承一个类的同时实现多个接口;
多个接口的实现
public class InterImpl implements Inter1,Inter2,Inter3{}
public class 类名 implements 接口名1,接口名2,接口名3{}
继承一个类的同时 实现多个接口
public class InterImpl extends InterClass implements Inter1,Inter2,Inter3{}
public class 子类名 extends 父类名 implements 接口名1,接口名2,接口名3{}
③接口和接口的关系
继承关系,可以单继承,也可以多继承
接口与接口直接关系:单继承、多继承都可以。
public interface Inter1 extends Inter2,Inter3{}
public interface 接口名1 extends 接口名2,接口名3{}
抽象类和接口的区别
类别 | 抽象类 | 接口 |
---|---|---|
成员区别 | 变量、常量;构造方法; 抽象方法,非抽象方法 | 常量; jdk1.7之前抽象方法;jdk1.7之后加了默认方法、静态方法 |
关系区别 | 类与类:继承,单继承 类与接口:实现,单实现、多实现 接口与接口:继承,单继承、多继承 | |
设计理念区别 | 对类抽象,包括属性、行为 | 对行为抽象,主要是行为 |
添加新的方法 | 给抽象类添加新方法,提供默认实现,就不需要改现有代码 | 接口中添加新方法,必须修改该接口的实现类 |
理解xhj:
门和报警的关系:
门有开和关两属性,现在有些门具有报警功能,具体的设计。
①都采用抽象类的方式,那么开门、关门、报警这些方法按照抽象方法写入抽象类中,继承抽象类的子类都具备了报警方法,但有些门可能不具备报警功能。
②都采用接口的形式。同理接口的实现类都具有报警方法,但是有些门可能不具备报警功能。
③最好的方式是:开门、关门采用抽象类定义,报警使用接口定义。
案例:运动员和教练
需求:
有乒乓球运动员和篮球运动员,乒乓球教练和篮球教练。为了出国交流,跟乒乓球相关的人员都需要学习英语。分析那些具体类、那些抽象类、那些接口,并用代码实现。
分析:
从具体到抽象》
具体的类:乒乓球运动员、篮球运动员、乒乓球教练、篮球教练
抽象类: ① 运动员类 教练类
② 人类
接口》
学习英语;
抽象类:
// 127-test6
public abstract class Coach extends Person {
public Coach(){}
public Coach(String name,int age){
super(name,age);
}
public abstract void teach();
}
//抽象人类
public abstract class Person {
public String name;
public int age;
public Person(){}
public Person(String name,int age){
this.name = name;
this.age = age;
}
public void setName(String name){
this.name = name;
}
public String getName(){
return name;
}
public void setAge(int age){
this.age = age;
}
public int getAge(){
return age;
}
public abstract void eat();
}
public abstract class Player extends Person {
//继承抽象类 会报错;解决方式①定义子类为抽象类②重写抽象类父类的所有抽象方法
public Player(){}
public Player(String name,int age){
super(name,age);
}
public abstract void study();
}
接口:
//说英语接口
public interface SpeakEnglish {
public abstract void speak();
}
具体类:(篮球)
// 篮球教练类 具体类
public class BasketballCoach extends Coach {
// 由于其继承的是Coach 抽象类,所以需要重写其中的抽象方法;
// Coach继承于 Person 抽象类,所以也需要重写其中的抽象方法。
@Override
public void eat() {
System.out.println("篮球教练饮食健康");
}
@Override
public void teach() {
System.out.println("篮球教练教运球和投球");
}
//两个构造方法
public BasketballCoach() {
}
public BasketballCoach(String name, int age) {
super(name, age);
}
}
// 篮球运动员类 具体类
public class BasketballPlayer extends Player {
@Override
public void study() {
System.out.println("篮球运动员学习运球和投篮");
}
@Override
public void eat() {
System.out.println("篮球运动员吃蛋白粉");
}
public BasketballPlayer() {
}
public BasketballPlayer(String name, int age) {
super(name, age);
}
}
具体类:(乒乓球)
// 乒乓球教练 具体类
public class PingPangCoach extends Coach implements SpeakEnglish{
@Override
public void teach() {
System.out.println("乒乓球教练教接球和罚球");
}
@Override
public void eat() {
System.out.println("乒乓球教练吃维生素含量多的饭");
}
@Override
public void speak() {
System.out.println("乒乓球教练说英语");
}
public PingPangCoach() {
}
public PingPangCoach(String name, int age) {
super(name, age);
}
}
// 乒乓球运动员类 具体类
public class PingPangPlayer extends Player implements SpeakEnglish {
@Override
public void speak() {
System.out.println("乒乓球运动员学英语");
}//重写接口SpeakEnglish中的抽象方法
@Override
public void study() {
System.out.println("乒乓球运动员学习接球和打球");
}//重写抽象类Player中的抽象方法
@Override
public void eat() {
System.out.println("乒乓球运动员吃蛋白棒");
}//重写抽象类Player中继承的抽象类Person中的抽象方法eat
public PingPangPlayer() {
}
public PingPangPlayer(String name, int age) {
super(name, age);
}
}
测试:
public class PersonDemo {
public static void main(String[] args) {
PingPangPlayer ppp = new PingPangPlayer();
ppp.setName("马龙");
ppp.setAge(35);
System.out.println(ppp.getName() + ", " + ppp.getAge());
ppp.eat();//Person抽象类的抽象方法
ppp.study();//Player抽象类的抽象方法
ppp.speak();//SpeakEnglish接口的抽象方法
System.out.println("---------------");
BasketballPlayer bbb = new BasketballPlayer("姚明",45);
System.out.println(bbb.getName() + ", " + bbb.getAge());
bbb.eat(); //Person抽象类的抽象方法
bbb.study();//Player抽象类的抽象方法
// bbb.speak();//报错,BasketballPlayer类中没有 speak方法
}
}
接口组成更新
接口组成:
常量 public static final(修饰符可省略);抽象方法 public abstract(修饰符可省略);默认方法(java8);静态方法(java8);私有方法(java9);
接口中的默认方法
格式:
public default 返回值类型 方法名(参数列表){}
其中public可以省略
案例:
// public default void show3(){}
实现类重写默认方法的格式:
@Override
public 返回值类型 方法名(参数列表){}
注意事项:
- 在接口中实现抽象方法的升级(再添加抽象方法),使用默认方法升级,接口的实现类可以重写默认方法、也可以不重写。
- public 可以省略,default不可以省略。
- 一个实现类 不能同时实现两个具有相同默认方法的接口。
代码:
package itiheima312.test11;
public interface MyInterface {
void show1();
void show2();
* 证明接口中添加抽象方法 如果是默认方法则实现类不需要修改;不是则需要修改实现类
// void show3();
* 接口中添加抽象方法,实现类如果没有重写该方法,实现类会报错。
default void show4() { }
* 接口中添加默认方法,实现类没有重写该方法也不会报错。
}
public class MyInterfaceImplOne implements MyInterface,MyInterface2 {
@Override
public void show1() {
System.out.println("One show1");
}
@Override
public void show2() {
System.out.println("One show2");
}
}
// 测试代码
public class MyInterfaceDemo {
public static void main(String[] args) {
// 按照多态的形式创建对象
MyInterfaceImplOne mio = new MyInterfaceImplOne();
mio.show1();
mio.show2();
}
}
public interface MyInterface2 {
void method();
default void show4(){};
* 接口MyInterface2 和 接口 MyInterface 有相同的默认方法show4 所以同时实现这两个接口的类会报错。
}
接口中的静态方法
格式:
[public] static 返回值类型 方法名(参数列表){}
案例:
// public static void show(){}
注意:
- 接口的实现类对象 可以调用 抽象方法、默认方法;
- 当实现类 实现了 两个接口,且这两个接口都有静态方法method,那么使用 实现类对象.method 调方法就不知道 调的是哪个方法,所以接口中的静态方法只能用 接口名.方法名 调用;
- public可以省略,static 不能省略。
代码:
package itiheima312.test12;
public interface Inter {
void show(); // 抽象方法
default void method(){ // 默认方法
System.out.println("Inter 中的默认方法启动了");
}
static void test(){ //静态方法
System.out.println("Inter 中的静态方法启动了");
}
}
public interface Inter2 {
void show2(); // 抽象方法
default void method(){ // 默认方法
System.out.println("Inter2 中的method方法启动了");
}
}
* 一个实现类 不能继承两个具有相同默认方法的接口
/*public class InterImpl implements Inter,Inter2{
@Override
public void show2() {
System.out.println("InterImpl 中的show2方法实现了");
}*/
public class InterImpl implements Inter{
@Override
public void show() {
System.out.println("InterImpl 中的show方法实现了");
}
}
public class InterDemo {
public static void main(String[] args) {
InterImpl ii = new InterImpl();
ii.show();
ii.method();
* 报错 这个在编译阶段就会报错。
* 接口中的静态方法调用 接口名.方法名
// ii.test();
Inter.test(); // 使用 接口.静态方法 实现调用
}
}
接口中的私有方法
出现原因:
当两个默认方法或者静态方法中包含一段相同的代码实现时,会将相同的代码抽取成一个共性方法,不让别人使用,用私有给藏起来。
格式:
格式1:
private 返回值类型 方法名(参数列表){}
格式2:
private static 返回值类型 方法名(参数列表){}
注意事项:
- 默认方法可以调用私有的静态方法和非静态方法;
- 静态方法只能调用私有的静态方法;
代码:
package itiheima312.test13;
public interface Inter {
default void show1(){
System.out.println("show1 start");
// System.out.println("you are my pretty sunshine");
// System.out.println("All things come to someone who wait");
method();
System.out.println("show1 end");
}
default void show2(){
System.out.println("show2 start");
// System.out.println("you are my pretty sunshine");
// System.out.println("All things come to someone who wait");
method();
System.out.println("show2 end");
}
static void method1(){
System.out.println("method1 start");
// System.out.println("you are my pretty sunshine");
// System.out.println("All things come to someone who wait");
method();
System.out.println("method1 end");
}
static void method2(){
System.out.println("method2 start");
// System.out.println("you are my pretty sunshine");
// System.out.println("All things come to someone who wait");
method();
System.out.println("method2 end");
}
private static void method(){
System.out.println("you are my pretty sunshine");
System.out.println("All things come to someone who wait");
}
}
// 测试类。
public class InterDemo {
public static void main(String[] args) {
InterImpl i = new InterImpl();
i.show1();
System.out.println("----------");
i.show2();
System.out.println("----------");
Inter.method1();
System.out.println("-------------");
Inter.method2();
}
}