java复习面向对象(二)
java复习面向对象(二)
1、static关键字![]()
-
举例图片
-
静态变量
-
使用static修饰的成员变量是静态变量
-
如果一个成员变量使用了关键字static,那么这个变量不属于对象自己,而属于所在的类多个对象共享同一份数据
-
推荐写法:
类.静态变量
,该写法可以直接观看出变量是静态变量; -
不推荐写法:
对象.静态变量
- 写成对象名.静态变量,javac编译的时候会编译成
类.静态变量
- 写成对象名.静态变量,javac编译的时候会编译成
-
-
静态方法
- 使用static修饰的成员方法是静态方法
- 1、静态不能直接访问非静态;
- 内存中先有静态的内容,后有非静态的内容。类似与先人不知道后人,但后人知道先人。
- 2、静态方法中不能使用this
- 原因:this代指当前对象,谁调用方法,谁就是当前对象。
-
一旦使用了static修饰的成员方法,那么就成为了静态方法。静态方法不属于对象,而属于类。 如果没有static关键字,那么必须首先创建对象,然后才能通过对象使用他; 如果有static关键字,那么不需要创建对象,直接通过类名就能使用它; 无论是成员变量还是成员方法。如果有了static关键字修饰,都推荐使用类名进行调用。 静态变量:类名称.静态变量; 静态方法:类名称.静态方法; 注意: 1、静态不能直接访问非静态; - 内存中**先**有静态的内容,**后**有非静态的内容。类似与先人不知道后人,但后人知道先人。 2、静态方法中不能使用this 原因:this代指当前对象,谁调用方法,谁就是当前对象。
1.1代码示例
-
package com.one; public class DemoStatic { public static void main(String[] args) { Student one =new Student("章北海",35); one.room="自然选择号";//正确写法但是不推荐 //写成对象名.静态变量,javac编译的时候会编译成`类.静态变量` Student.room="蓝色空间号";//推荐写法,直接看出来room是静态变量 Student two =new Student("东方延续",35); System.out.println(two.getName()+"是"+two.room+"舰长"+two.getId());//东方延续是自然选择号舰长,并未设置,但是会共享数据 System.out.println("==============================="); MyClass.mystatic(); MyClass myone= new MyClass(); myone.method(); } }
- ```jaVA
package com.one;
public class Student {
private int id;
private String name;
private int age;
//如果一个成员变量使用了关键字static,那么这个变量不属于对象自己,而属于所在的类多个对象共享同一份数据
static String room;
private static int idCounter=0;//学号计数器,每当new了一个对象的时候计数器++
//生成全参的构造方法
public Student(String name, int age) {
this.name = name;
this.age = age;
this.id=idCounter++;
}
//生成无参的构造方法
public Student() {
idCounter++;
}
/*生成对应的访问和设置函数*/
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 getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
}
-
package com.one public class MyClass { int num=0; static int numstatic=1; public static void mystatic(){ System.out.println("我是一个静态方法"); //System.out.println(this);//报错,静态方法中不能写this; //System.out.println(num);//静态方法不能直接访问成员变量 System.out.println("静态方法可以直接访问静态变量"+numstatic);//静态方法可以直接访问静态变量 } public void method(){ System.out.println("我是一个不同的成员方法"); System.out.println("成员方法可以直接访问成员变量"+num); System.out.println("成员方法可以直接访问静态变量"+numstatic); //成员方法可以直接调用静态方法不用写类名 mystatic(); } }
1.2 静态内存图
1.3 静态代码块
-
特点;当第一次用到本类的时候,静态代码块执行唯一的一次
-
静态内容总是先于非静态加载,所以静态代码块比构造方法先执行
-
静态代码块的用途
- 用来一次性地对静态成员变量进行赋值
- 经常用于JDBCZ中的。
-
静态代码块: 类{ static{ //静态代块的内容 } }
-
public class Person { static { System.out.println("静态代码执行"); } public Person(){ System.out.println("构造方法执行"); } }
-
package com.one; public class Demo1 { public static void main(String[] args) { Person one=new Person(); Person two=new Person(); /*console 静态代码执行 构造方法执行 构造方法执行*/ } }
2、继承
-
继承是多态的前提,如果没有继承就没有多态
-
继承主要解决的就是共性抽取
-
图示
2.1继承的特点与语法
-
特点
- 子类可以用友父类的“内容”
- 子类还可以用友自己的专有内容
-
语法
//在继承关系中,“子类就是一个父类”,也就是说子类可以被当做父类看待 //例如:父类是员工,子类是讲师,那么讲师就是一个员工;关系is-a // 父类的格式就是普通类的定义格式; package com.one; public class Employee { int num=100; public void method(){ System.out.println("我是员工类中的的方法"); } }
package com.one; //继承的格式 public class Teacher extends Employee{ int num=200; public void methodZi(){ //就近使用本类中的num,没有则想上寻找 System.out.println(num); } public void three(){ int num=300; System.out.println("局部变量"+num);//局部变量300 System.out.println("本类成员变量"+this.num);//本类成员变量200 System.out.println("父类的成员变量"+super.num);//父类的成员变量100 } }
package com.one; /* 在父类的继承关系中,如果成员变量重名,则创建子类对象时,访问有两种方式 直接通过子类对象访问成员变量 等号左边是谁,就优先用谁,没有则向上找 间接通过成员方法访问成员变量 该方法属于谁,就优先用谁,没有则向上找 即:就近原则 * */ public class DemoExtends { public static void main(String[] args) { Teacher teacher= new Teacher(); teacher.method();//我是员工类中的的方法;执行了员工类中方法; System.out.println(teacher.num); teacher.methodZi();//200 teacher.methodFu();//100 } }
-
补充知识点
//三种变量的使用方法 System.out.println("局部变量"+num);//局部变量300 System.out.println("本类成员变量"+this.num);//本类成员变量200 System.out.println("父类的成员变量"+super.num);//父类的成员变量100
2.2 重名方法的执行
- 创建的对象是谁就优先用谁如果没有,则向上找;
- 无论是成员方法还是成员变量,如果没有都是向上找父类,不会向下找子类
2.3 覆盖重写
- 重写(Override)
- 在继承关系当中,方法的名称一样参数列表一样
- 重写也叫覆盖,覆写
- 特点:创建的是子类对象,优先用子类方法;
- 重载(Overload)
- 同一类中方法的名称一样,参数的列表不一样
2.4 注意事项
-
注解@Override
- 覆盖重写时必须保证父子类方法名称相同,参数列表也相同。
- @Override:写在方法前面用来检测是不是有效的覆盖重写
- 这个注解就算不写,也是正确的的方法覆盖重写;
-
返回值
- 子类的返回值必须小于等于父类的返回值范围
- 扩展:java.lang.Object类是所有类的父类,
-
权限修饰符
-
权限等级:public>protected>(default)>private
-
defualt不是关键字,而是什么都不写留空
-
子类方法的权限必须要大于等于父类的权限
-
-
package cn.day03; public class Fu { public void method(){ System.out.println("父类的方法"); } void sayhello(){ //默认权限等级是(default) System.out.println("我是父类"); } public Object showclass(){ return null; } }
-
package cn.day03; public class Zi extends Fu{ @Override//本注解检测是不是有效的覆盖重写,可以不写,一般都会写上 public void method(){ System.out.println("子类的方法"); } @Override public void sayhello(){ System.out.println("我的权限等级大于(default)"); } @Override public String showclass(){ //String属于子类返回值小于等于父类烦人范围 return "HELLO WORLD"; } }
-
package cn.day03; public class DemoExtends { public static void main(String[] args) { Zi zi=new Zi(); zi.method(); String str=zi.showclass(); System.out.println(str); } } /*console 子类的方法 HELLO WORLD */
2.5 继承中的构造方法
-
子类构造方法中默认隐含的
super()
调用,所以一定先调用父类构造,后执行子类的构造。 -
子类的构造可以通过super关键字调用父类的重载构造。
-
super父类构造调用,必须是子类构造方法的第一个语句。不能一个子类调用多个super构造。
-
总结
- 子类必须地调用父类的构造方法,不写则赠送super(),写了则用指定的super调用,super只能有一个还必须是第一个;
-
package cn.day03; public class Fu { public Fu(){ System.out.println("父类构造方法"); } public Fu(int num){ System.out.println("父类重载构造方方法"); } }
-
package cn.day03; public class Zi extends Fu{ public Zi(){ super(20);//调用父类重载的有参构造方法,必须写在构造方法的第一行; System.out.println("子类构造方法"); } }
-
package cn.day03; public class DemoExtends { public static void main(String[] args) { Zi zi=new Zi(); } } /* 父类重载构造方方法 子类构造方法 */
2.6 继承的三大特征
- Java语言是单继承的
- 一个类的直接父类只能有唯一一个
- JAVA可以多重继承
- Object是所有类的父类;
java.lang.Object
- Object是所有类的父类;
- 一个父类的直接父类是唯一的,但是一个父类可以拥有多个子类
- 对比:Python语言是多继承的,Python中类可以继承多个类;
2.7 继承的小案例
-
群主发红包
-
package demo.jc; public class User { private double money; private String name; public User() { } public User(double money, String name) { this.money = money; this.name = name; } public void show(){ System.out.println("我是"+name+"我有"+money+"块钱"); } public double getMoney() { return money; } public void setMoney(double money) { this.money = money; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
-
package demo.jc; import java.util.ArrayList; public class Manger extends User{ public Manger() { } public Manger(double money, String name) { super(money, name); } public ArrayList<Double> send(double totalmoney,int count){ //创建一个集合,用来存储红包金额 ArrayList<Double> redlist =new ArrayList<>(); //首先查看群主有多少钱 double leftMoney=super.getMoney(); if(totalmoney>leftMoney){ System.out.println("余额不足"); return redlist;//返回空集合 } //扣钱,在重新设置余额 super.setMoney(totalmoney-leftMoney); double avg=totalmoney/count; double mod=totalmoney%count; //除不开的余数放在最后一个红包中 /*count.fori*///直接生成for循环 for (int i = 0; i < count-1; i++) { redlist.add(avg); } //最后一个红包设置大的金额 double last=avg+mod; redlist.add(last); return redlist; } }
-
package demo.jc; import java.util.ArrayList; import java.util.Random; public class Member extends User{ public Member() { } public Member(double money, String name) { super(money, name); } public void recive(ArrayList<Double> list){ //使用random的匿名对象,使用size获取列表长度;设置好范围 int index=new Random().nextInt(list.size()); //使用remove从当前集合删除,并返回对应值;即获得抢到的红包, double delta=list.remove(index); double money=super.getMoney(); //原来金额加回去; super.setMoney(delta+money); } }
-
package demo.jc; import javax.xml.crypto.Data; import java.util.ArrayList; public class DemoMain { public static void main(String[] args) { Manger boss=new Manger(); Member employee1=new Member(); Member employee2=new Member(); Member employee3=new Member(); boss.setName("章北海"); boss.setMoney(100.0); boss.show(); employee1.setName("东方延续"); employee1.show(); employee2.setName("丁仪"); employee2.show(); employee3.setName("褚岩"); employee3.show(); System.out.println("=================="); ArrayList<Double> list =boss.send(20,3); employee1.recive(list); employee2.recive(list); employee3.recive(list); employee1.show(); employee2.show(); employee3.show(); } }
3、super关键字
-
用法
- 在子类的成员方法中,访问父类的成员变量。
- 在子类的成员方法中,访问父类的成员方法。
- 在子类的构造方法中,访问父类的构造方法。
-
package cn.day03; public class Zi extends Fu{ public Zi(){ super(20);//调用父类重载的有参构造方法,必须写在构造方法的第一行; System.out.println("子类构造方法"); } @Override//本注解检测是不是有效的覆盖重写 public void method(){ super.method();//调用父类的成员方法 System.out.println("==============="+super.num);//调用父类的成员变量; System.out.println("子类的方法"); } @Override public void sayhello(){ System.out.println("我的权限等级大于(default)"); } @Override public String showclass(){ //String属于子类返回值小于等于父类烦人范围 return "HELLO WORLD"; } }
4、this关键字
-
用法
- 在本类成员方法中,调用本类成员变量。
- 在本类成员方法中,调用本类另一个成员方法。
- 在本类的构造方法中,调用另一个构造方法。
- 注意:this(....)调用也必须是构造方法的第一个语句。唯一一个;
- 使用this的时候,构造方法不在默认赠送super()构造方法;
- super()与this不能够同时使用;
-
package cn.day03; public class DemoZi extends Fu{ public DemoZi(){ //使用this后不在调用super() this(20); } public DemoZi(int num){ System.out.println("我被调用了"); } String str="Hello World"; public void saystr(){ bb();//普通也可以调用 //也可以使用this调用 this.bb(); System.out.println(this.str); } public void bb(){ System.out.println("bbbbbbbb"); } }
5、抽象类
-
如果父类的方法中不确定如何进行{}方法体的实现,那么这应该就是一个抽象方法.
-
举例图示
-
注意事项
- 抽象类不能创建对象,创建会报错;
- 即只要使用了关键字
abstrace
修饰的类都不能创建对象,即使该类不包含抽象方法; - 抽象类不一定包含抽象方法;
- 包含抽象方法的类一定是抽象类;
- 即只要使用了关键字
- 抽象类中可以有构造方法,是供子类初始化父类成员时使用的;与普通类差别不大;
- 抽象类不一定包含抽象方法,包含抽象方法的类一定是抽象类;
- 抽象类的子类,必须重写所有的抽象方法,否则编译报错;除非子类也是抽象类;
- 抽象类不能创建对象,创建会报错;
-
package cn.day03; /* 抽象方法:就是加上abstract关键字,然后去掉大括号直接分号结束。 抽象类:抽象方法所在的类,必须是抽象类才行。在class之前写上abstract即可; 即含有抽象方法类一定是抽象类; 使用抽象类和抽象方法: 1、不能直接创建new抽象类对象 2、必须使用一个子类来继承抽象父类 3、子类必须覆盖重写抽象类当中的所有抽象方法; 覆盖重写(实现):子类去掉抽象方法中的abstract关键字,然后补上大括号 4、创建子类对象使用; * */ public abstract class DemoCx { //这是一个抽象方法,代表吃东西,具体吃什么不知道(大括号中有什么内容,不确定); public abstract void eat(); public abstract void sleep(); //普通成员方法 public DemoCx(){ System.out.println("抽象类的构造方法执行"); } public void say(){ System.out.println("Hello World"); } }
-
package cn.day03; //抽象类的子类,必须重写所有的抽象方法,否则编译报错;除非子类也是抽象类 public abstract class Dog extends DemoCx{ @Override public void eat() { //重写父类的抽象方法 System.out.println("哈士奇吃雪!!!"); } } package cn.day03; public class ErHa extends Dog{ @Override public void sleep() { //直接父类已经实现了一个抽象方法;因此只要再实现另一个抽象方法就可以 System.out.println("哈士奇已经睡着了"); } }
-
package cn.day03; public class DeMu extends DemoCx{ public DeMu(){ System.out.println("德牧的构造方法执行"); } //直接重写所有的抽象方法 @Override public void eat() { } @Override public void sleep() { } }
-
package cn.day03; public class DemoMain { public static void main(String[] args) { // DemoCx aa= new DemoCx() ;//错误写法抽象类不能直接new对象 // Dog dog=new Dog();//子类没有完全重写父类的构造方法因此也是抽象类 // dog.eat(); ErHa erha=new ErHa(); erha.eat(); erha.sleep(); System.out.println("======================"); DeMu demu=new DeMu(); demu.eat(); demu.sleep(); } } /*Console 抽象类的构造方法执行 哈士奇吃雪!!! 哈士奇已经睡着了 ====================== 抽象类的构造方法执行 德牧的构造方法执行 */
6、接口
6.1 接口举例及定义
-
接口是一种公共的规范标准;只要符合标准就可以通用;
-
图示
-
定义
-
接口是一种引用数据类型;最重要的内容就是其中的抽象方法;
-
接口是多个类的公共规范;
-
定义接口的格式
public interface 接口名称{ } //接口名称的命名规范与类名称一致;
-
-
接口中包含的内容
-
如果是java7(jdk1.7)
1.常量
2、抽象方法
-
如果是Java8(jdk1.8)
- 默认方法
- 静态方法
-
如果是Java9
- 5、私有方法
-
6.2 接口的使用
使用步骤
1、接口不能直接使用,必须使用实现类来实现该接口;
-
格式
public class 实现类名称 implements 接口名称{} //实现类名称命名通常采用`接口名字`+`impl`来命名
2、创建实现类对象进行使用
- 实现类名称命名通常采用
接口名字
+impl
来命名
3、注意事项
-
如果实现类并没有覆盖重写接口中所有的抽象方法,那么这个实现类就必须是一个抽象类;
-
接口中不包含普通方法,因为不写关键字会有默认的
public
+abstract
直接成为抽象方法;- 接口当中定义抽象方法,修饰符必须是两个关键字:public abstract
- 这两个关键字可以选择性的省略不写
4、示例
-
package day04; /* * 在任何版本的Java中,接口都能定义抽象方法; * 注意: * 接口当中定义抽象方法,修饰符必须是两个关键字:public abstract * 这两个关键字可以选择性的省略不写; * */ public interface MyInterfaceAbs { //定义的是抽象方法 public abstract void method(); //省略关键字abstract public void method1(); //省略关键字public abstract void method2(); //省略关键字public和abstract void method3(); /*以上三种省略关键字都属于抽象方法;熟练之后可以使用省略关键字的写法*/ } //实现类 package day04; //关键字implements public class MyInterfaceImpl implements MyInterfaceAbs{ @Override public void method() { System.out.println("第1个方法"); } @Override public void method1() { System.out.println("第一个方法"); } @Override public void method2() { System.out.println("第二个方法"); } @Override public void method3() { System.out.println("第三个方法"); } }
package day04; public class DemoInterface { public static void main(String[] args) { //实例化实现类的对象; MyInterfaceImpl impl=new MyInterfaceImpl(); impl.method(); impl.method1(); impl.method2(); impl.method3(); } }
6.3 接口中的默认方法
-
从Java8开始,接口支持默认方法;
-
用途
- 用来解决接口升级;因为接口定义完成之后会有其他方法加入,如果需要去所有的实现类中重写则比较繁琐;因此使用接口的默认方法进行升级,则实现类不重写,也不会报错;
- lamdba表达式和函数式编程,接口的默认方法可以拼接函数模型;
-
格式
public default 返回值 方法名(){}
-
注意事项
- 接口的默认方法,可以通过接口的实现类对象,直接调用
- 接口的默认方法,也可以被接口的实现类重写覆盖;
-
编码示例
package day04; public interface MyInterfaceAbs { //定义的是抽象方法 public abstract void method(); //省略关键字abstract public void method1(); //省略关键字public abstract void method2(); //省略关键字public和abstract void method3(); /*以上三种省略关键字都属于抽象方法;熟练之后可以使用省略关键字的写法*/ //添加一个默认方法 public default void say(){ System.out.println("Hello World"); } public default void sayHello(){ System.out.println("我是接口的默认方法,现在还没有被重写"); } } package day04; public class MyInterfaceImpl implements MyInterfaceAbs{ @Override public void method() { System.out.println("第1个方法"); } @Override public void method1() { System.out.println("第一个方法"); } @Override public void method2() { System.out.println("第二个方法"); } @Override public void method3() { System.out.println("第三个方法"); } @Override public void sayHello(){ //重写接口的默认方法,也可以不重写 System.out.println("我重写了接口的默认方法"); } }
package day04; public class DemoInterface { public static void main(String[] args) { MyInterfaceImpl impl=new MyInterfaceImpl(); impl.method(); impl.method1(); impl.method2(); impl.method3(); System.out.println("========"); //直接调用,默认方法直接被实现类实现; impl.say(); //调用覆盖后的默认方法 impl.sayHello(); } }
6.4 接口中的静态方法
-
格式:将默方法中的
default
变换成static
即可; -
接口静态方法的使用
- 通过接口名称直接调用静态方法;
接口名称.静态方法名称()
-
注意事项
- 不能通过接口实现类的对象来调用接口当中的静态方法;
- 一个实现类可能会实现多个接口,因此实现类对象调用易发生冲突;
-
示例
- 在上述接口中添加静态方法,并直接调用;
package day04; public interface MyInterfaceAbs { public static void sayStatic(){ System.out.println("我是接口的静态方法"); } }
package day04; public class DemoInterface { public static void main(String[] args) { MyInterfaceImpl impl=new MyInterfaceImpl(); impl.method(); impl.method1(); impl.method2(); impl.method3(); System.out.println("========"); //直接调用 impl.say(); //调用覆盖后的默认方法 impl.sayHello(); System.out.println("===================="); MyInterfaceAbs.sayStatic(); } } /* 第1个方法 第一个方法 第二个方法 第三个方法 ======== Hello World 我重写了接口的默认方法 ==================== 我是接口的静态方法 */
6.5 接口中的私有方法
-
从java9开始才支持私有方法
- 静态私有方法
- 普通私有方法
-
本人电脑装的是java8顾不做展示;使用方法和类中的私有方法使用相同;
-
6.7 接口中的常量
-
接口中也可以定义
成员变量
,但必须使用public static final
三个关键字进行修饰; -
从效果上看这就是接口的常量;
-
格式
public static final 数据类型 常量名称=数据值;
- 备注:一旦使final关键字进行修饰,说明不可改变;
-
注意事项
- 接口中的常量,可以省略
public static final
;不写这三个关键字,会默认添加; - 接口中的常量必须直接赋值,不能不赋值;
- 接口中常量的名称,使用完全大写的字母,用下划线分割,(推荐命名规则)例如
MY_CLASS
- 接口中的常量,可以省略
-
示例
package day04; public interface MyInterfaceAbs { //定义接口中的成员变量,即常量 public static final int MY_CLASS=6; //省略关键字不写,效果相同 String SCHOOL_NAME="哔哩哔哩大学"; }
package day04; public class DemoInterface { public static void main(String[] args) { MyInterfaceImpl impl=new MyInterfaceImpl(); impl.method(); impl.method1(); impl.method2(); impl.method3(); System.out.println("========"); //直接调用 impl.say(); //调用覆盖后的默认方法 impl.sayHello(); System.out.println("===================="); MyInterfaceAbs.sayStatic(); System.out.println("===================="); //输出常量 System.out.println(MyInterfaceAbs.SCHOOL_NAME); System.out.println(MyInterfaceAbs.MY_CLASS); } } /*Consloe 第1个方法 第一个方法 第二个方法 第三个方法 ======== Hello World 我重写了接口的默认方法 ==================== 我是接口的静态方法 ==================== 哔哩哔哩大学 6 */
6.8 接口知识点截图
6.9 接口中的注意事项
-
1、接口没有静态代码块和构造方法;
-
2、一个类的直接父类是唯一的,但一个类可以实现多个接口;
-
格式:
public class Myinterface implements MyinterfaceA,MyinterfaceB{ //覆盖重写所有的抽象方法 }
-
-
3、如果实现类的多个接口当中,存在重复抽象方法,那么只需要覆盖重写一次即可;
-
4、如果实现类没有覆盖重写所有接口的抽象方法,那么实现类就必须是一个抽象类;
-
5、如果实现类所实现的多个接口中,存在重复的默认方法,那么实现类一定要对冲突的默认方法进行覆盖重写;
-
6、一个类如果直接父类当中的方法,和接口中的默认方法发生了冲突;优先用父类中的方法;
-
示例代码
接口A,B的代码
package day04; public interface MyInterfaceA { public abstract void methodA(); public abstract void func(); public default void hand(){ System.out.println("欢迎来到,傻狗之够"); } public default void func2(){ System.out.println("接口A的默认方法"); } } package day04; public interface MyInterfaceB { public abstract void mthodB(); public abstract void func(); public default void func2(){ System.out.println("接口B的默认方法"); } public default void sayhello(){ System.out.println("HelloWorld,接口B"); } }
实现类的代码
package day04; public class InterfaceImpl implements MyInterfaceA,MyInterfaceB{ @Override public void methodA() { } @Override public void mthodB() { } //func方法是两个接口都有的抽象方法,只需要覆盖一次即可 @Override public void func() { } //两个接口中都存在func2的默认方法,因此需要在实现类中进行覆盖重写一次 @Override public void func2() { System.out.println("我该执行谁的"); //不写谁都不调用,但是只要进行了覆盖重写,即使没有内容依然正确; MyInterfaceB.super.func2(); } }
package day04; public class Fu extends FuO{ public void sayhello(){ System.out.println("Hello World,父类方法"); } } package day04; public class Zi extends Fu implements MyInterfaceB{ //实现类既可以继承同时还可以实现接口; @Override public void mthodB() { } @Override public void func() { } }
主方法
package day04; public class Demo2Interface { public static void main(String[] args) { InterfaceImpl impl=new InterfaceImpl(); impl.func2(); System.out.println("======================="); Zi zi =new Zi(); //直接父类的方法与默认方法冲突后,优先使用父类的方法,非直接父类效果一样 zi.sayhello();//Hello World,父类方法, } } /*Console 我该执行谁的 接口B的默认方法 ======================= Hello World,父类方法 */
6.10 接口中的多继承
-
类与类之间是单继承的关系,直接父类只有一个;
-
类与接口之间是多实现的,一个类可以实现多个接口
-
接口与接口之间是多继承的
-
注意事项
1、多个父接口当中的抽象方法如果重复,没关系。因为抽象方法没有方法体;
2、多个父接口当中的默认方法如果重复,那么子接口必须进行默认方法的覆盖重写,而且带着default关键字。
-
-
代码示例
父接口
package day04; public interface MyInterfaceC { public abstract void func(); public abstract void funcC(); public default void sayhello(){ System.out.println("Hello World接口C"); } public default void edg(){ System.out.println("edg夺冠了!"); } } package day04; public interface MyInterfaceD { public abstract void func(); public abstract void funcD(); public default void sayhello(){ System.out.println("Hello World接口D"); } }
子接口
package day04; public interface MyInterface extends MyInterfaceC,MyInterfaceD{ //同时继承了C,D接口,而且C,D同时包含func();方法,但因为func()是抽象方法,所以没关系; public abstract void mthod(); //接口继承中抽象方法不用重写; //C,D同时包含默认方法sayhello(),所以必须要重写sayhello方法,而且必须加上关键字default; @Override default void sayhello() { MyInterfaceC.super.sayhello(); } }
实现类
package day04; public class FuO implements MyInterface{ @Override public void mthod() { } @Override public void func() { } @Override public void funcD() { } @Override public void funcC() { } }
主方法
package day04; public class Demo2Interface { public static void main(String[] args) { InterfaceImpl impl=new InterfaceImpl(); impl.func2(); System.out.println("======================="); Zi zi =new Zi(); //直接父类的方法与默认方法冲突后,优先使用父类的方法,非直接父类效果一样 zi.sayhello();//Hello World,父类方法, System.out.println("======================="); FuO aa =new FuO(); aa.edg(); } } /* 我该执行谁的 接口B的默认方法 ======================= Hello World,父类方法 ======================= edg夺冠了! */
7、多态
-
extends继承和implements实现是多态性的前提
-
对象具有多态性
-
代码当中体现多态性就是一句话,父类引用,指向子类对象
-
格式
父类 对象名= new 子类();
接口 对象名 =new 实现类();
7.1 多态中的成员变量与方法
-
成员变量
- 多态中成员变量的调用与普通类调用一样,创建对象时等号左边是谁,优先用谁。
- 编译看左边,运行还看左边;
-
成员方法:
- 看new的是谁,就优先用谁,没有则向上找;
- 编译看左边,运行看右边;
7.2 多态的优势
- 无论右边
new
对象的时候换成那个子类对象,等号左边调用方法都不会发生变化;
7.3 对象的转型
-
向上转型:向上转型一定是安全的;
-
弊端:对象一旦向上转型,就无法使用子类特有的方法;
-
-
向下转型
-
-
instanceof判断
-
原来不是则会报转型错误的异常,因此一定要做转型判断 instanceof
-
//格式 if (obj instanceof Zi) { Zi aa = (Zi) obj; }
-
-
代码示例
package day05; public class Fu { public void func(){ System.out.println("父类方法"); } public void Dad(){ System.out.println("伟大的父爱"); } } package day05; public class Zi extends Fu { @Override public void func(){ System.out.println("子类方法"); } public void vip(){ System.out.println("我是子类特有的方法"); } } package day05; public class Dog extends Fu{ }
主方法
package day05; public class DemoMutil { //多态:创建对象的时候左侧是父类,右侧是子类 public static void main(String[] args) { Fu obj = new Zi(); //同名优先使用子类的方法 obj.func(); //子类没有的向上寻找父类的方法 obj.Dad(); // obj.vip();//报错,无法使用子类特有的方法,因为使用多态后对象默认向上转型,因此无法使用, //解决方法:将对象向下转型,注意:向下转型必须原来是 ,才能够进行向下转型; // 语法格式 // 子类名称 对象名 =(子类名称)父类对象 //进行向下转型的判断,必须原来是,才能转换为原来的 if (obj instanceof Zi) { Zi aa = (Zi) obj; aa.vip(); } //原来不是则会报转型错误的异常,因此一定要做转型判断 instanceof if (obj instanceof Dog) { Dog bb = (Dog) obj; } else { System.out.println("我没有通过验证,Obj原来不是Dog"); } } } /* 子类方法 伟大的父爱 我是子类特有的方法 我没有通过验证,Obj原来不是Dog */
8、final关键字
- 代表不可变的,最终的;
- 四种用法
8.1 修饰类
-
当使用final关键字修饰类的时候,该类不能有任何子类,父类依然正常
package day05; // 当使用final关键字修饰类的时候,该类不能有任何子类,父类依然正常; // 由于本类没有子类,因此本类中的方法无法被覆盖重写,但是该类依旧可以覆盖重写父类的方法 public final class MyClass { public void dreadmd(){ System.out.println("该类不能被继承"); } }
8.2 修饰方法
-
当final关键字用来修饰一个方法的时候,这个方法就是最终方法,也就是不能被覆盖重写;
-
注意
- 对于类、方法来说,abstract关键字和final关键字不能同时使用,因为矛盾;
- abstract :必须要子类实现,被覆盖重写;
- final,不能有子类,不能被覆盖重写
- 对于类、方法来说,abstract关键字和final关键字不能同时使用,因为矛盾;
-
格式
package day05; public class FuFinal { public final void readself(){ System.out.println("此方法被final修饰了,不能被覆盖重写"); } }
//错误代码展示 package day05; public class ZiFinal extends FuFinal{ //报错,无法覆盖重写父类中被final修饰的方法 // @Override // public final void readself(){ // System.out.println("此方法被final修饰了,不能被覆盖重写"); // } public abstract final void error(){ System.out.println("final关键字和abstract不能同时使用"); } }
8.3 修饰局部变量
-
使用final修饰后,这个变量就不能修改
-
不可变
- 对于基本类型来说,不可变说的是变量中的数据不可变;
- 对于引用类型来说,不可变说的是变量中的地址值不可变;
-
示例代码
package day05; public class DemoFinal { public static void main(String[] args) { final int num=666; //使用final修饰后,这个变量就不能修改 //一次赋值,终生不改 System.out.println(666); //num=222;//错误写法不支持 //num=666;错误写法 //使用final只允许赋值一次,即使相同也不可以二次赋值 final int age; age=18;//正确写法,唯一一次赋值, /*****************/ System.out.println("============================"); //对于基本类型来说,不可变说的是变量中的数据不可变; //对于引用类型来说,不可变说的是变量中的地址值不可变; final Student stu =new Student("傻狗"); System.out.println(stu.getName()); stu.setName("哈士奇");//内容发生改变,但是地址值没有发生改变; System.out.println(stu.getName());//哈士奇 } }
8.4 final 修饰成员变量
-
对于成员变量来说,如果使用final关键字进行修饰,那么这个变量照样不可变;
-
由于成员变量具有默认值,所以用final之后必须手动赋值,不会再给默认赋值;
-
对于final的成员变量,要么使用直接赋值,要么通过构造方法赋值;二者选其一;
-
必须保证类当中所有重载的构造方法,都最终会对final的成员变量进行赋值;
-
示例代码
package day05; public class Person { // private final String name;//不会在默认赋值 //private final String name="傻狗";手动赋值 private final String name; public Person() { name="二哈"; } public Person(String name) { this.name = name; } //以上两个构造方法都实现了对name的赋值; public String getName() { return name; } //使用final后不能在被修改 // public void setName(String name) { // this.name = name; // } }
真累啊!
记录不易,转载请注明出处;