面向对象(下)
1.类的继承
一.什么是继承,有什么用?
继承:在现实世界当中也是存在的,例如:父亲很有钱,几子不用努力也很有钱
继承的作用:
基本作用:子类继承父类,代码可以得到复用。(这个不是重要的作用,是基本作用
主要(重要)作用:因为有了继承关系,才有了后期的方法覆盖和多态机制
二.特性
① B类继承 A类,则称 A类为超类(superclass)、父类、基类,B类则称为子类(subclass)、
派生类、扩展类。
② java 中的继承只支持单继承,不支持多继承,C++中支持多继承,这也是 java 体
现简单性的一点,换句话说,java 中不允许这样写代码:class B extends A,C{ }。
③ 虽然 java 中不支持多继承,但有的时候会产生间接继承的效果,例如:class C
extends B,class B extends A,也就是说,C 直接继承 B,其实 C 还间接继承 A。
④ java 中规定,子类继承父类,除构造方法不能继承外,剩下都可以继承.私有属性无法在子类中直接访问.(父类中private修饰的不能在子类中直接访问,但可以间接访问例如私有属性用set和get方法)
⑤ java 中的类没有显示的继承任何类,则默认继承 Object 类,Object 类是 java 语言提供的根类(老祖宗类),也就是说,一个对象与生俱来就有 Object 类型中所有的特征。
⑥ 继承也存在一些缺点,例如:CreditAccount 类继承 Account 类会导致它们之间的耦合度非常高,Account 类发生改变之后会马上影响到CreditAccount 类。
代码
public class ExtendTest01{
public static void main(String[] args){
Account act=new Account();
act.setActno("11213");
act.setBalance(1243);
System.out.println(act.getActno()+"余额"+act.getBalance());
CreditAccount ca =new CreditAccount();
ca.setActno("23425");
ca.setBalance(-1234);
ca.setCredit(0.332);
//ca.dosome();
ca.doSome();
System.out.println(ca.getActno()+"余额"+ca.getBalance()+"信誉度"+ca.getCredit());
}
}
class Account{ //父类
//属性
private String actno;
private double balance;
//构造方法
public Account(){
}
public Account(String actno,double balance){
this.actno=actno;
this.balance=balance;
}
//setter and getter
public void setActno(String actno){
this.actno=actno;
}
public String getActno(){
return actno;
}
public void setBalance(double balance){
this.balance=balance;
}
public double getBalance(){
return balance;
}
}
class CreditAccount extends Account { //子类
//除了构造方法其他都继承
//私有类可以继承但无法直接访问
/*继承了
private String actno;
private double balance;*/
private double credit;
public CreditAccount(){
}
public void doSome(){
//System.out.println(actno); wrong
//this.actno=actno; wrong
//子类间接访问父类私有属性
System.out.println(getActno());
}
//setter and getter
/*继承了
public void setActno(String actno){
this.actno=actno;
}
public String getActno(){
return actno;
}
public void setBalance(double balance){
this.balance=balance;
}
public double getBalance(){
return balance;
}*/
public void setCredit(double credit){
this.credit=credit;
}
public double getCredit(){
return credit;
}
}
11213余额1243.0
23425
23425余额-1234.0信誉度0.332
三.引申
1.1、测试:子类继承父类之后,能使用子类对象调用父类方法吗?
可以,因为子类继承了父类之后,这个方法就属于子类了当然可以使用子类对象来调用
1.2、在实际开发中,满足什么条件的时候,我可以使用继承呢?
凡是采“is a"能描述的,都可以继承
例如:
Cat is a animal:猫是一个动物
Dog is a Anima1:狗是一个动物
Credi tAccount is a Account:信用卡账户是一个银行账户
四.解析prinltn()方法
大致原理
public class Test {
static Student2 stu=new Student2();
public static void main(String[] args) {
Test.stu.exam();
//此处对应System.out.prinltn();
}
}
class Student2{
public void exam(){
System.out.println("fuck exam");
}
}
fuck exam
五.Object类
任何一个类,没有显示继承任何类,默认继承 Object类
1.toString()方法
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
当直接输出一个引用的时候, println()方法会先自动调用引用. tostring()〃,然后输出 tostring()方法的执行结果
public class ExtendTest05 {
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
public static void main(String[] args) {
ExtendTest05 ex=new ExtendTest05();
System.out.println(ex.toString());
System.out.println(ex);
fuck ck=new fuck();
System.out.println(ck);
}
}
class fuck{
}
ExtendTest05@723279cf
ExtendTest05@723279cf
fuck@3d494fbf
Object深入理解点击即可
2.super关键字
一.super概述
super
①super能出现在实例方法和构造方法中
②super的语法是:" super."、 super()
③super不能使用在静态方法中
④super.大部分情况下是可以省略的
⑤super.什么时候不能省略呢?
super()只能出现在构造方法第一行,通过当前的构造方法去调用"父类"中的构造方法,目的是:创建子类对象的时候,先初始化父类型特征
二.super和this的区别
super 使用在构造方法中
语法格式为:super(实际参数列表),
举例
public class SuperTest01 {
public static void main(String[] args) {
new B();
}
}
class A{
public A(){
System.out.println("A的无参构造方法生效");
}
public A(int a){
System.out.println("A的有参构造方法生效");
}
}
class B extends A{
public B(){
this(100);
System.out.println("B的无参构造方法");
}
public B(int b){
super(100); //此处不写则为情况2
System.out.println("B的有参构造方法");
}
}
正常运行
A的有参构造方法生效
B的有参构造方法
B的无参构造方法
情况2
A的无参构造方法生效
B的有参构造方法
B的无参构造方法
结论
①当一个构造方法第一行:既没有this()又没有 super()的话,默认会有一个 super()
表示通过当前子类的构造方法调用父类的无参数构造方法所以必须保证父类的无参数构造方法是存在的
注意:
②this()和 super()不能共存,它们都是只能出现在构造方法第一行
③无论是怎样折腾,父类的构造方法是一定会执行的。(百分百的)
在java语言中不管是是new什么对象,最后老祖宗的 Object类的无参数构造方法一定会执行。( Object类的无参数构造方法是处于栈顶部〃)
栈顶的特点:
最后调用,但是最先执行结束
后进先出原则
④以后写代码的时候,一个类的无参数构造方法还是建议大家手动的写出来如果无参数构造方法丢失的话,可能会影响到子类对象的构建
三.this 和 super
public class SuperTest03 {
public static void main(String[] args) {
CreditAccount c1=new CreditAccount();
System.out.println(c1.getActno()+","+c1.getBalance()+","+c1.getCredit());
CreditAccount c2=new CreditAccount("234",134,0.99);
System.out.println(c2.getActno()+","+c2.getBalance()+","+c2.getCredit());
}
}
class Account{ //父类
//属性
private String actno;
private double balance;
//构造方法
public Account(){
}
public Account(String actno,double balance){
this.actno=actno;
this.balance=balance;
}
//setter and getter
public void setActno(String actno){
this.actno=actno;
}
public String getActno(){
return actno;
}
public void setBalance(double balance){
this.balance=balance;
}
public double getBalance(){
return balance;
}
}
class CreditAccount extends Account { //子类
//除了构造方法其他都继承
//私有类可以继承但无法直接访问
/*继承了
private String actno;
private double balance;*/
public CreditAccount(String acton,double balance,double credit){
super(acton,balance);
}
private double credit;
public CreditAccount(){
//super()
//this.credit=0.0;都执行了,只是程序没写出而已
}
public void setCredit(double credit){
this.credit=credit;
}
public double getCredit(){
return credit;
}
}
null,0.0,0.0
234,134.0,0.0
内存图
四.super不能省略的情况
super.什么时候不能省略?
父中有,子中又有,如果想在子中访问父的特征, super.不能省略
public class SuperTest05 {
public static void main(String[] args) {
vip v=new vip("张三");
v.shopping();
}
}
class Customer{
String name;
public Customer() {
}
public Customer(String name) {
// super();
this.name = name;
}
/* public void dosome(){
System.out.println(this.name+"do some");
System.out.println(name+"do some");
//System.out.println(super.name+"do some");
}*/
}
class vip extends Customer{
String name;//java允许在子类中和父类一样的同名变量
public vip() {
}
public vip(String name) {
super(name);
}
public void shopping(){
System.out.println(this.name+"正在购物");
System.out.println(super.name+"正在购物");
System.out.println(name+"正在购物");
}
}
null正在购物
张三正在购物
null正在购物
内存图
五.super调用父类方法
在父和子中有同名的属性,或者说有相同的方法,
如果此时想在子类中访问父中的数据,必须使用 “super."加以区分
super.属性名 【访问父类的属性】
super.方法名(实参)【访问父类的方法】
super(实参)【调用父类的构造方法】
public class SuperTest07 {
public static void main(String[] args) {
Cat c=new Cat();
c.moveTest();
}
}
class Animal{
public void move(){
System.out.println("Animal move");
}
}
class Cat extends Animal{
@Override
public void move() {
System.out.println("Cat move");
}
public void moveTest(){
this.move();
super.move();
move();
}
}
Cat move
Animal move
Cat move
六.super的理解
①super不是引用。 super也不保存内存地址, super也不指向任何对象
②super只是代表当前对象内部的那一块父类型的特征。
public class SuperTest06 {
public void dosome(){
System.out.println(this);
//System.out.println(super.);java: 需要<标识符>
}
public static void doOther(){
//System.out.println();
}
public static void main(String[] args) {
SuperTest06 st=new SuperTest06();
st.dosome();
}
}
Test01@723279cf
final关键字
一.概述
①final是java语言中的一个关键字
②final表示最终的,不可变的
③final可以修饰变量以及方法,还有类等
④final修饰的类无法继承
⑤final修饰的方法无法覆盖
⑥final修饰的局部变量,一旦赋值不能重新赋值
⑦final修饰引用不能再次赋值,但被指向的对象是可以修改的
⑧ final 修饰的实例变量必须显示初始化
二.final修饰的类无法继承
public class FinalTest01 {
public static void main(String[] args) {
}
}
final class A{
}
/*
class B extends A{
}
//errorjava: 无法从最终A进行继承*/
/*
class B extends String{
}
java: 无法从最终java.lang.String进行继承*/
java String类
三.final修饰的方法无法覆盖
提示:final控制不了能不能调用的问题。
final管的是啥?
final修饰的表示最后的,不能变的,不能改的
public class FinalTest01 {
public static void main(String[] args) {
//A a=new B();
// a.dosome();
}
}
class A{
public final void dosome(){
}
}
/*
class B extends A{
@Override
public void dosome() {
System.out.println("b 's dosome");
}
}
java: B中的dosome()无法覆盖A中的dosome()
被覆盖的方法为final*/
四.final修饰局部变量
final修饰的局部变量,一旦赋值不能重新赋值
public class FinalTest01 {
public static void main(String[] args) {
final int m=30;
/*m=0;
java: 无法为最终变量m分配值*/
}
}
五.final修饰引用
该引用只能指向1个对象,并且它只能永远指向该对象,无法再指向其它对象并且在该方法执行过程中,该引用指向对象之后,该对象不会被垃圾回收器回收直到当前方法结束,才会释放空间.
public class FinalTest02{
public static void main(String[] args) {
final Person p1=new Person(30);
/* p1=new Person(30);
//java: 无法为最终变量p1分配值*/
p1.age=40;
System.out.println(p1.age);
}
}
class Person{
int age;
public Person(int age) {
this.age = age;
}
}
40
//p1 采用 final 修饰,主要限制了 p1 指向堆区中的地址不能修改(也就是p1只能指向一个对象)
//p1 指向的对象的属性是可以修改的
六.final修饰实例变量
final修饰的实例变量,系统不负责赋默认值,要求程序员必须手动赋值,这个手动赋值,在变量后面赋值可以,在构造方法中赋值也可以
public class FinalTest03 {
public static void main(String[] args) {
}
}
class User{
final double weight=80;
final double height;
public User(){
this.height=80;
}
}
public class FinalTest04 {
public static void main(String[] args) {
System.out.println(Chinese.COUNTRY);
}
}
class Chinese{
String idCard;
String name;
public static final String COUNTRY="中国";
}
中国
实例变量既然使用final修饰了,说明该实例变量值不会随着对象的变化而变化
该实例变量前面应该添加: static关键字,变为静态的,存储在方法区,既然别人改不了,我们就可用public修饰符修饰
3.抽象类和接口
一.抽象类概述
①类和类之间具有共同特征,将这些共同特征提取出来,形成的就是抽象类
②类本身是不存在的,所以抽象类无法创建对象《无法实例化》
③类到对象是实例化。对象到类是抽象
语法
[修饰符列表] abstract class类名{
//定义抽象方法
[修饰符] abstract 方法返回值 方法名([参数列表]);
//其他方法或属性
}
抽象类Test
public class AbstractTest01 {
public static void main(String[] args) {
/*new Account();java: Account是抽象的; 无法实例化*/
/* 能不能使用多态?
父类型引用指向子类型对象。*/
Account a=new creditAccount();//向上转型。(自动类型转换)
a.withdraw();
/*
以后你都是调用的a.XX
a的类型是 Account, Account是抽象的
面向抽象编程,不要面向具体编程,降低程序的耦合度,提高程序的扩展力
这种编程思想符合CP原则*/
}
}
abstract class Account{
public Account(){
System.out.println();
}
public abstract void withdraw();
}
class creditAccount extends Account{
public creditAccount(){
}
@Override
public void withdraw() {
System.out.println("withdraw test");
}
}
/* final abstract class test extends Account{
//抽象类的子类可以是抽象类
// java: 非法的修饰符组合: abstract和final
}
*/
withdraw test
①抽象类也属于引用数据类型
②抽象类是无法实例化的,无法创建对象的,所以抽象类是用来被子类继承的
③final和 abstract不能联合使用,这两个关键字是对立的
④抽象类的子类可以是抽象类
⑤抽象类虽然无法实例化,但是抽象类有构造方法,这个构造方法是供子类使用的
⑥抽象方法表示没有实现的方法,没有方法体的方法。例如:
public abstract void withdraw();
抽象方法特点是:
特点1:没有方法体,以分号结尾
特点2:前面修饰符列表中有 abstract关键字
⑦抽象类不一定有抽象方法,抽象方法必须出现在抽象类中
抽象类中的普通方法就是没有abstact关键字的也可以写,同时可以不必实现。
⑧一个非抽象的类继承抽象类,必须将抽象类中的全部抽象方法实现了这是java语法上强行规定的必须的,不然编译器就报错了这里的覆盖或者说重写,也可以叫做实现。(对抽象的实现。)
二.接口概述
①接口也是一种引用数据类型。编译之后也是一个class字节码文件。
②接口是完全抽象的。(抽象类是半抽象。)或者也可以说接口是特殊的抽象类
③接口语法
[修饰符列表] interface接口名{}
接口支持多继承
④接口中只包含常量和抽象方法
⑤接口中所有的元素都是public修饰的。(都是公开的。)接口中的方法默认都是 public abstract 的(抽象方法),不能更改,接口中的变量默认都是 public static final 类型的,不能更改,所以必须显示的初始化
⑥接口中的方法都是抽象方法,所以接口中的方法不能有方法体**
可以和多态联合使用
⑦java中,一个类实现某个接口,必须重写接口中的所有方法吗?
不一定,关键要看子类是否是抽象类。
如果子类是非抽象类,则必须实现接口中的所有方法;
如果子类是抽象类,则可以不实现接口中的所有方法,因为抽象类中允许有抽象方法的存在!
⑧extends和implements可以共存,extends在前,implements在后。
public class InterfaceTest01 {
public static void main(String[] args) {
System.out.println(MyMath.pai);
// new MyMath();java: MyMath是抽象的; 无法实例化
MyMath a=new MyMathimp();//多态联合使用
System.out.println(a.sub(10,20));
System.out.println(a.sum(20,30));
}
}
interface A{
}
interface B extends A{
}
interface C extends A,B{
}
interface MyMath{
//常量
//public static final double pai=3.1415926;
double pai=3.1415926;//public static final double省略
// public abstract int sum(int a,int b);
int sum(int a,int b);//public abstract省略
int sub(int a,int b);
}
class MyMathimp implements MyMath{
public int sum(int a,int b){
return a+b;
}
public int sub(int a,int b){
return a-b;
}
}
3.1415926
-10
50
接口和类用implements关键字,可以理解为继承,就是实现
1.extends和implements一起用
public class InterfaceTest03 {
public static void main(String[] args) {
A a=new C();
a.m1();
// a.m2();java: 找不到符号
// 符号: 方法 m2()
B b=(B)a;
//经过测试:接口和接口之间在进行强制类型转换的时候,没有继承关系,也可以强转
//但是一定要注意,运行时可能会出现 ClassCastException异常
b.m2();
}
}
interface A{
void m1();
}
interface B{
void m2();
}
class C implements A,B{
public void m1(){
System.out.println("m1");
}
@Override
public void m2() {
System.out.println("m2");
}
}
m1
m2
java中类和类只支持单继承。实际上单继承是为了简单而出现的,现实世界中存在多继承,java中的接口弥补了单继承带来的缺陷
public class InterfaceTest04 {
public static void main(String[] args) {
flyable a=new Cat();
a.fly();
}
}
class Animal{
}
interface flyable{
void fly();
}
class Cat extends Animal implements flyable{
public void fly(){
System.out.println("fly");
}
}
fly
二.接口在开发中的作用
注意:接口在开发中的作用,类似于多态在开发中的作用
多态:面向抽象编程,不要面向具体编程。降低程序的耦合度。提高程序的扩展力
总结一句话:三个字解耦合
public class Test {
public static void main(String[] args) {
//创建厨师对象
FoodMenu cooker1=new AmericanCooker();
FoodMenu cooker2=new ChineseCooker();
//创建顾客对象
Customer customer=new Customer(cooker2);
//顾客点菜
customer.order();
}
}
interface FoodMenu{
void xiHongShi();
void qinJiaoRous();
}
class ChineseCooker implements FoodMenu{
public void xiHongShi(){
System.out.println("中国西红柿");
}
public void qinJiaoRous(){
System.out.println("中国青椒肉丝");
}
}
class AmericanCooker implements FoodMenu{
@Override
public void qinJiaoRous() {
System.out.println("American qinjiaosous");
}
@Override
public void xiHongShi() {
System.out.println("American XiHongshi");
}
}
class Customer {
private FoodMenu foodMenu;
public Customer() {
}
public Customer(FoodMenu foodMenu) {
this.foodMenu = foodMenu;
}
public FoodMenu getFoodMenu() {
return foodMenu;
}
public void setFoodMenu(FoodMenu foodMenu) {
this.foodMenu = foodMenu;
}
public void order(){
foodMenu.qinJiaoRous();
foodMenu.xiHongShi();
}
}
中国青椒肉丝
中国西红柿
面向接口编程,可以降低程序的耦合度,提高程序的扩展力。符合OCP开发原则
接口的使用高不开多态机制。(接口+多态才可以达到降低耦合度。)
接口可以解耦合,解开的是谁和谁的耦合!!!
任何一个接口都有调用者和实现者
接口可以将调用者和实现者解耦合
调用者面向接口调用
实现者面向接口编写实现
以后进行大项目的开发,一般都是将项目分高成一个模块一个模块的
模块和模块之间采用接口衔接。降低耦合度
三.is-a,is-like-a,has-a
is a(继承)、has a(关联)、like a(实现)
Is a:
Cat is a animal(猫是一个动物)
凡是能够满足is a的表示v继承关系〃
a extends b
has a:
i has a pen(我有一支笔)
凡是能够满足has a关系的表示关联关系
关联关系通常以属性的形式存在
A
like a:
Cooker1 ike a FoodMenu(厨师像一个菜单一样)
凡是能够满足like a关系的表示实现关系〃
实现关系通常是:类实现接口
A implements B
4.多态
一.方法覆盖
① 方法覆盖发生在具有继承关系的父子类之间,这是首要条件;
② 覆盖之后的方法与原方法具有相同的返回值类型、相同的方法名、相同的形式参数列表
③覆盖之后的方法不能比原方法拥有更低的访问权限,可以更高(学习了访问控制权限修饰符之后你就明白了);
④ 覆盖之后的方法不能比原方法抛出更多的异常,可以相同或更少(学习了异常之后就明白了);
⑤与了多态机制之后相同的返回值类型"可以修改一下吗?
对于返回值类型是基本数据类型来说,必须一致
对于返回值类型是引用数据类型来说,重写之后返回值类型可以变的更小但不能变大(但意义不大,开发无意义)
public class OverrideTest01 {
public static void main(String[] args) {
Bird2 b=new Bird2();
b.move2();
Cat2 c=new Cat2();
c.move2();
c.move2(1);//构成方法重载
}
}
class Animal2{
public void move2() {
System.out.println("fly");
}
}
class Bird2 extends Animal2 {
public void move2() {
System.out.println("I want fly");
}
}
/* private void move2(){
System.out.println("I want fly");
}
}*/
class Cat2 extends Animal2 {
public void move2(int i){
System.out.println("I want talk");
}
}
I want fly
fly
I want talk
私有方法不可覆盖,静态方法覆盖没什么意义
public class OverrideTest06{
private void dosome(){
System.out.println("private dosome method dosome execute");
}
public static void main(String[] args){
OverrideTest06 at=new T();
at.dosome();
}
}
class mytest{
public static void main(String[] args){
OverrideTest06 ot = new T();
ot.dosome();
}
}
class T extends OverrideTest06{
public void dosome(){
System.out.println("T 's public dosome method execute");
}
}
//经过测试,私有方法不可覆盖
注意事项
注意1:方法覆盖只是针对于方法,和属性无关。
注意2:私有方法无法爱盖
注意3:构造方法不能被继承,所以构造方法也不能被爱盖
注意4:方法覆盖只是针对于实例方法",静态方法覆盖”没有意义。
方法重载和方法覆盖有什么区别?
方法重载发生在同一个类当中
方法覆盖是发生在具有继承关系的父子类之间。
方法重载是一个类中,方法名相同,参数列表不同
方法覆盖是具有继承关系的父子类,并且重写之后的方法必须和之前的方法一致:方法名一致、参数列表一致、返回值类型一致
方法重载和方法覆盖区别与联系
方法重载和方法覆盖区别与联系
二.多态
1.概述
多态是同一个行为具有多个不同表现形式或形态的能力。
在 java 中允许这样的两种语法出现,一种是向上转型(Upcasting),一种是向下转型(Downcasting),向上转型是指子类型转换为父类型,又被称为自动类型转换,向下转型是指父类型转换为子类型,又被称为强制类型转换
无论是向上转型还是向下转型,两种类型之间必须要有继承关系,没有继承关系情况下进行向上转型或向下转型的时候编译器都会报错,
体会与描述(一个例子了解多态)
强转 Animal a2=new Cat() Cat c=(Cat) a2; 因为在编译阶段能调用哪些成员,是由编译类型决定的这里也就是Animal,所以你想调用子类特有的方法(父类没有此方法而子类特有)就找不到该方法,Animal.catchMouse()编译报错,所以需要向下转型(强制类型转换) c.catchMouse();
public class Text01 {
public static void main(String[] args) {
Animal a=new Bird();
a.move();
Animal a2=new Cat();
a2.move();
Cat c=(Cat) a2;
c.catchMouse();
Animal a3=new Bird();
//Cat c2=(Cat)a3;
// Exception in thread "main" java.lang.ClassCastException: class Bird cannot be cast to class Cat (Bird and Cat are in unnamed module of loader 'app')
// at Text01.main(Text01.java:10) 类型转换异常
if(a3 instanceof Cat){
Cat c2=(Cat)a3;
}
System.out.println(a3 instanceof Cat);
}
}
class Animal{
public void move(){
System.out.println("..");
}
}
class Cat extends Animal{
@Override
public void move() {
System.out.println("Cat talk");
}
public void catchMouse(){
System.out.println("catch mouse");
}
}
class Bird extends Animal{
@Override
public void move() {
System.out.println("Bird is fly");
}
}
Bird is fly
Cat talk
catch mouse
false
就是说编译时绑定Animal的move()方法,而运行时绑定创建真正对象的move()方法
Animal a=new Bird();
a.move();
这里编译绑定Animal的move()方法,运行时绑定Bird类的的move()方法,因为brid属于Bird类
2.instanceof运算符
语法
(引用 instanceof 类型)
新的内容,运算符:
instanceof(运行阶段动态判断)
第一: instanceof可以在运行阶段动态判断引用指向的对象的类型
第二: instanceof的语法:
(引用 instanceof类型)
第三: instanceof运算符的运算结果只能是:true/ false
第四:c是一个引用,c变量保存了内存地址指向了堆中的对象
假设( c instanceof cat)为true表示:
c引用指向的堆内存中的java对象是一个Cat
假设( c instanceof cat)为fa1se表示:
c引用指向的堆内存中的java对象不是一个cat
借用上述bird和cat类
public class Test03 {
public static void main(String[] args) {
AnimalTest t=new AnimalTest();
t.test(new Bird());
t.test(new Cat());
}
}
public class AnimalTest {
public void test(Animal a){
if(a instanceof Cat){
Cat c=(Cat)a;
c.catchMouse();
}else if(a instanceof Bird){
Bird b=(Bird)a;
b.move();
}
}
}
Bird is fly
catch mouse
从代码看出,你可以向下转型调出子类特有的方法
5.内部类
①匿名内部类
什么是内部类?
内部类:在类的内部又定义了一个新的类。被称为内部类
②内部类的分类:
静态内部类:类似于静态变量
实例内部类:类似于实例变量
局部内部类:类似于局部变量
③使用内部类编写的代码,可读性很差。能不用尽量不用
匿名内部类是局部内部类的一种
package 匿名内部类;
public class Test02 {
public static void main(String[] args) {
Mymath mm=new Mymath();
//Compute c=new computeLi();
//mm.mySum(c,10,20);
mm.mySum(new Compute() {
@Override
public int sum(int a, int b) {
return a+b;
}
}, 10, 20);
}
}
interface Compute{
public abstract int sum(int a,int b);
}
/*
class computeLi implements Compute{
public int sum(int a,int b){
return a+b;
}
}
*/
class Mymath{
public void mySum(Compute c,int x,int y){
int retValue=c.sum(x,y);
System.out.println(x+"+"+y+"="+retValue);
}
}
10+20=30
④匿名内部类是局部内部类的一种。
因为这个类没有名字而得名,叫做匿名内部类
⑤学习匿名内部类主要是让大家以后在阅读别人代码的时候,能够理解
并不代表以后都要这样写。因为匿名内部类有两个缺点
缺点1:太复杂,太乱,可读性差
缺点2:类没有名字,以后想重复使用,不能用
⑥不理解算了,你只要记住这种写法就行
6.Lambda表达式
7.异常
异常处理