定义:某一类事物的多种存在形态
◆例:动物中猫、狗
◆猫这个对象对应的类型是猫类型
猫 c=new 猫();
◆同时猫也是动物中的一种,也可以把猫称为动物。
动物 y=new 猫();
动物是猫和狗具体事物中抽取出来的父类型
父类型引用了子类对象。
体现:
父类或者接口的引用指向自己的子类对象或者接收自己的子类对象
作用:
多态的存在提高了程序的扩展性和后期可维护性
弊端:
只能使用父类的引用访问父类中的成员
前提:
·需要存在继承或者实现关系
·需要覆盖操作
特点:
成员函数:
编译时:要查看引用变量所属的类中是否有所调用的成员
在运行时:要查看对象所属的类中是否有所调用的成员
成员变量:
只看引用变量所属的类
示例1:(使用子类都有的方法)
abstract class Animal{
abstrac tvoid eat();
}
class Cat extends Animal{
public void eat(){
System.out.println(“吃鱼”);
}
public void catchMouse(){
System.out.println(“抓老鼠”);
}
}
class Dog extends Animal{
public void eat(){
System.out.println(“吃骨头”);
}
public void kanJia(){
System.out.println(“看家”);
}
}
class Pig extends Animal{
public void eat(){
System.out.println(“吃饲料”);
}
public void gongDi(){
System.out.println(“拱地”);
}
}
class DuoTaiDemo{
public static void main(String[] args){
function(newCat());
function(newDog());
function(newPig());
}
public static void function(Animal a){
a.eat();
}
}
运行结果:
吃鱼
吃骨头
吃饲料
示例2:(使用子类特有方法)
abstract class Animal{
abstract void eat();
}
class Cat extends Animal{
public void eat(){
System.out.println("吃鱼");
}
public void catchMouse(){
System.out.println("抓老鼠");
}
}
class Dog extends Animal{
public void eat(){
System.out.println("吃骨头");
}
public void kanJia(){
System.out.println("看家");
}
}
class Pig extends Animal{
public void eat(){
System.out.println("饲料");
}
public void gongDi(){
System.out.println("拱地");
}
}
class DuoTaiDemo{
public static void main(String[] args){
function(newCat());
function(newDog());
function(newPig());
}
public static void function(Animal a){
a.eat();
if(a instanceof Cat){
Cat c=(Cat)a;
c.catchMouse();
}else if(a instanceof Dog){
Dog d=(Dog)a;
d.kanJia();
}else{
Pig p=(Pig)a;
p.gongDi();
}
}
}
运行结果:
吃鱼
抓老鼠
吃骨头
看家
饲料
拱地
附注:
类型提升(向上转型)
Anaimal a=new Cat();
a.eat();
如果要调用猫的特有方法,就要强制将父类转成子类类型的话(向下转型)
Cat c=(Cat)a;
c.catchMouse();
我们能转换的是父类应用指向自己的子类对象,该应用可以被提升,也可以被强制转换,多态自始自终都是子类对象在做着变化
像Animal a=new Animal();是不允许出现的。
instanceof用于判断对象的类型,格式:对象 instanceof类型(类类型接口类型)
练习1:需求:基础班学生(学习、睡觉)、高级班学生(学习、睡觉)
代码实现:
abstract class Student{
public abstract void study();
public void sleep(){
System.out.println("sleep");
}
}
class DoStudent{
public void doSome(Student stu){
stu.study();
stu.sleep();
}
}
class BaseStudent extends Student{
public void study(){
System.out.println("base study");
}
//覆盖父类sleep功能
public void sleep(){
System.out.println("base sleep");
}
}
class AdvStudent extends Student{
public void study(){
System.out.println("adv study");
}
}
class DuoTaiDemo{
public static void main(String[] args){
DoStudent ds = new DoStudent();
ds.doSome(newBaseStudent());
ds.doSome(newAdvStudent());
}
}
运行结果:
base study
base sleep
adv study
sleep
练习2:调用时的细节
class Fu{
static int num = 5;
void method1(){
System.out.println("fumethod_1");
}
void method2(){
System.out.println("fumethod_2");
}
static void method4(){
System.out.println("fumethod_4");
}
}
class Zi extends Fu{
static int num = 8;
void method1(){
System.out.println("zimethod_1");
}
void method3(){
System.out.println("zimethod_3");
}
static void method4(){
System.out.println("zimethod_4");
}
}
class DuoTaiDemo{
public static void main(String[] args) {
Fu f = new Zi();
System.out.println(f.num);
f.method1();
f.method2();
f.method3();
Zi z = new Zi();
System.out.println(z.num);
z.method1();
z.method2();
z.method3();
}
}
运行结果:
5
zi method_1
zi method_2
fu method_3
8
zi method_1
zi method_2
zi method_3
总结:
1.在多态中成员函数的特点:
·在编译时期:参阅引用型变量所属的类中是否有调用的方法。如果有,编译通过,如果没有编译失败。
·在运行时期:参阅对象所属的类中是否有调用的方法。
成员函数在多态调用时,编译看左边,运行看右边。
2.在多态中,成员变量的特点:无论编译和运行,都参考左边(引用型变量所属的类)。
3.在多态中,静态成员函数的特点:无论编译和运行,都参考做左边。
练习3:(电脑运行实例——电脑运行基于主板)
代码实现:
interface PCI{
public void open();
public void close();
}
class NetCard implements PCI{
public void open(){
System.out.println("netcard open");
}
public void close(){
System.out.println("netcard close");
}
}
class SoundCard implements PCI{
public void open(){
System.out.println("SoundCard open");
}
public void close(){
System.out.println("SoundCard close");
}
}
class MainBoard{
publicvoid run(){
System.out.println("mainboardrun ");
}
//PCI p = new NetCard()//接口型引用指向自己的子类对象
public void usePCI(PCI p){
p.open();
if(p!=null){
p.close();
}
}
}
class DuoTaiDemo{
publicstatic void main(String[] args){
MainBoardmb=new MainBoard();
mb.run();
mb.usePCI(newNetCard());
mb.usePCI(newSoundCard());
}
}
运行结果:
mainboard run
netcard open
netcard close
SoundCard open
SoundCard close
二、内部类
将一个类定义在另一个类的里面,对里面那个类就称为内部类(内置类、嵌套类)
访问特点:
·内部类可以直接访问外部类中的成员,包括私有成员。(之所以可以直接访问外部类中的成员,是因为内部类中持有了一个外部类的引用,格式外部类名.this)
·而外部类要访问内部类中的成员必须要建立内部类的对象。
示例:
class Outer{
private int x=3;
class Inner{
int x=4;
void function(){
int x=6;
System.out.println("inner:"+Outer.this.x);
System.out.println("inner:"+this.x);
System.out.println("inner:"+x);
}
}
void method(){
Inner in=new Inner();
in.function();
}
}
class InnerClassDemo {
public static void main(String[] args) {
Outer out = new Outer();
out.method();
System.out.println("----------");
//直接访问内部类中的成员
Outer.Innerin=new Outer().new Inner();
in.function();
}
}
运行结果:
inner:3
inner:4
inner:6
----------
inner:3
inner:4
inner:6
访问格式(内部类的位置):
◆内部类定义在成员位置上:
1. 当内部类定义在外部类的成员位置上,而且非私有,可以在外部其他类中。可以直接建立内部类对象。
格式:外部类名.内部类名 变量名 = 外部类对象.内部类对象;
示例:Outer.Inner in=new Outer().newInner();
2.当内部类在成员位置上,就可以被成员修饰符所修饰
private:将内部类在外部类中进行封装
static:内部类就具备static的特性,当内部类被static修饰后,只能直接访问外部类中的static成员,出现了访问局限。
问:在外部其他类中,如何直接访问static内部类的非静态成员呢?
答:new Outer.Inner().function();
问:在外部其他类中,如何直接访问static内部类的静态成员呢?
答:Outer.Inner.function();
附注:当内部类中定义了静态成员,该内部类必须是static的,当外部类中的静态方法访问内部类时,内部类也必须是static的
示例:
class Outer{
private static int x=3;
static class Inner{
static void function(){
System.out.println("inner:"+x);
}
}
static class Inner2{
void show(){
System.out.println("inner2show");
}
}
public static void method(){
Inner.function();
newInner2().show();
}
}
class InnerClassDemo {
public static void main(String[] args) {
Outer.method();
System.out.println("---------");
//访问内部类的静态成员
Outer.Inner.function();
System.out.println("---------");
//访问内部静态类的非静态成员
newOuter.Inner2().show();
}
}
运行结果:
inner:3
inner2 show
---------
inner:3
---------
inner2 show
◆内部类定义在局部位置上:
1.不可以被成员修饰符修饰
2.可以直接访问外部类中的成员,因为还持有外部类中的引用。但是不可以访问它所在的局部中的变量。只能访问被final修饰的局部变量。
示例:
class Outer{
int x = 3;
void method(final int a){
final int y = 4;
class Inner{
void function(){
System.out.println(a);
//直接访问外部类中的成员
show();
}
}
new Inner().function();
}
void show(){
System.out.println("Outershow");
}
}
class InnerClassDemo{
public static void main(String[] args) {
Outer out = new Outer();
out.method(7);
out.method(9);
}
}
运行结果:
7
Outer show
9
Outer show
★匿名内部类:
就是内部类的简化写法
前提:
内部类可以继承或实现一个外部类或者接口
格式:
new外部类名或者接口名(){覆盖类或者接口中的代码(也可以自定义内容)}
简单理解:
就是建立一个带内容的外部类或者接口的子类匿名对象。
示例:
abstract class AbsDemo {
abstract void show();
}
class Outer {
int x = 3;
class Inner extends AbsDemo {
int num = 90;
void show() {
System.out.println("show:" + num);
}
void abc() {
System.out.println("hehe");
}
}
public void function() {
Inner in = new Inner();
in.show();
in.abc();
AbsDemo d = new AbsDemo() {
int num = 9;
void show() {
System.out.println("num==="+ num);
}
void abc() {
System.out.println("haha");
}
};
d.show();
//d.abc();//编译出错,因为AbsDemo类中没有abc方法
}
}
class InnerClassDemo {
public static void main(String[] args) {
newOuter().function();
}
}
运行结果:
show :90
hehe
num===9
练习:通过匿名内部类补足代码
interface Inter {
void method();
}
class Test {
// 补足代码(通过匿名内部类)
// static class Inner implements Inter{
// public voidmethod(){
// System.out.println("methodrun");
// }
// }
static Inter function() {
return new Inter() {
public void method() {
System.out.println("methodrun");
}
};
}
}
class InnerClassDemo {
public static void main(String[] args) {
//Test.function():Test类中有一个静态的方法function.method():function这个方法运算后的结果是一个对象,而且是一个Inter类型的对象,
//因为只有是Inter类型的对象,才可以调用method方法
Test.function().method();
show(newInter() {
public void method() {
System.out.println("methodshow run");
}
});
}
public static void show(Inter in) {
in.method();
}
}
运行结果:
method run
method show run