多态(重点)
多态的定义:
多态就是多种状态:同一个行为,不同的子类表现出来不同的形态。
多态指的就是同一个方法调用,然后由于对象不同会产生不同的行为。
多态的好处:
为了提高代码的扩展性,符合开闭原则。
(开闭原则:指的就是扩展是开放的,修改是关闭的。)
多态的要素(使用的前提条件):
- 继承: Cat extends Animal Pig extends Animal Dog extends Animal
- 重写:子类对父类的方法shout()重写
父类引用指向子类对象(父类做参数/返回值类型)
(声明父类,new子类) 向上转型
父类引用指向子类对象的说明:
//子类 对象名 = new 子类();
//对象可以调用重写父类的方法,也可以调用子类特有的方法(不支持多态)
//父类 对象名 = new 子类();
//只能调用重写父类的方法(相当是个父类对象),不能调用子类特有的方法(可向下转型进行修改,支持多态)
什么是动态绑定:
程序在编写时,父类做参数
但是程序在运行时,会根据传入的实际子类对象动态调用对应的方法。
什么题用多态:
肯定是两条线;两条线一定有交点;多态体现在第二条业务线上
(例如小女孩跟猫、狗、蛇玩)(没有第二条业务线就只定义继承即可)
看下面干货分享
public class Pet {
public void eat(){
System.out.println("宠物在吃东西...");
}
}
public class Cat extends Pet{//继承
@Override
public void eat() {//重写
System.out.println("猫在吃鱼!");
}
}
public class Dog extends Pet{//继承
@Override
public void eat() {//重写
System.out.println("狗吃骨头!");
}
}
/**
* 多态的第二条业务线
*/
public class Child {
// public void playPat(Cat cat){//说明:小朋友跟小猫玩
// cat.eat();
// }
// public void playPat(Dog dog){//说明:小朋友跟小狗玩
// dog.eat();
// }
//问题在动物多的时候要写好多方法
public void playPat(Pet pet){//父类做对象,程序会根据具体的子类对象,动态的调用子类的方法
System.out.print("小女孩看着");
pet.eat();
}
public void playPat2(Pet pet){
System.out.print("小女孩又来看");
if (pet instanceof Cat){//判断对象是不是该类型
((Cat)pet).eat();//向下转型,强转
}else if (pet instanceof Dog){
((Dog)pet).eat();//向下转型,强转
}
}
}
public class Demo1 {
public static void main(String[] args) {
Child child = new Child();
Pet cat = new Cat();//向上转型
child.playPat(cat);
child.playPat(new Dog());//直接传一个无参构造的狗对象
Cat c =(Cat)cat;//向下转型
c.eat();
child.playPat2(cat);
Pet dog = new Dog();
child.playPat2(dog);
}
/*
面向对象第三个特点:多态
封装(数据的安全、整合)->继承(代码的重用)->多态(代码的扩展)->(反射:把代码扩展到极致)
1.多态发生的场合:(不是所有题都适合用多态的)
1)题目中有两个业务线,第一条是继承线(1父,>=2子)
第二条业务线:一定有另外一个群体,该群体中的某一行为跟继承线中的多个子类是依赖关系
##(例如小女孩跟猫、狗、蛇玩)(没有第二条业务线就只定义继承即可)
2.什么是多态?(多态只关注行为(方法),不关注属性)
=====实现多态的前提条件(继承+重写方法)
1)不同的子类对象,作为参数在参与同一行为时,有不同的表现形式就叫多态。
2)动态绑定:程序在编写时,父类做参数
但是程序在运行时,会根据传入的实际子类对象动态调用对应的方法。
3.实现多态的前提条件:继承、方法的重写、父类引用指向子类对象。(声明父类,new子类)向上转型
4.解释【父类引用指向子类对象】
子类 对象名 = new 子类();
对象可以调用重写父类的方法,也可以调用子类特有的方法(不支持多态)
父类 对象名 = new 子类();
只能调用重写父类的方法(相当是个父类对象),不能调用子类特有的方法(可向下转型进行修改,支持多态)
5.多态的实现方法有两种:
父类做参数
父类做返回值
6.Java中引用数据类型的类型转换
子类<父类
【向上转型】小转大:自动转换:声明父类,new子类
Pet pet = new Cat();
注意:向上转型后,创建的对象只能调用重写父类的方法(相当是个父类对象),不能调用子类特有的方法(可再向下转型进行修改)
【向下转型】大转小,强自转或:声明子类,父类强转成子类
Cat cat = (Cat) pat;
注意:想要向下转型该对象曾经必须向上转型过,向下转型时类型要匹配,否则报ClassCastException错误
【解决方案】instanceof判断类型避免异常
if(i instanceof Dog){//判断i对象是不是狗类型的
((Dog)i).eat();
}
Java中基本数据类型的类型转换
boolean不参加转换,(char,byte,short)<int<long<float<double
小转大:自动转换 大转小:强制转换
*/
}
Java中引用数据类型的类型转换(重点)
子类<父类
向上转型(向父类转)
小转大:自动转换:声明父类,new子类
Pet pet = new Cat();
注意:向上转型后,创建的对象只能调用重写父类的方法
(相当是个父类对象),不能调用子类特有的方法(可再向下转型进行修改)
向下转型(向子类转)
大转小:强自转或:声明子类,父类强转成子类
Cat cat = (Cat) pat;
注意:想要向下转型该对象曾经必须向上转型过,向下转型时类型要匹配
,否则报ClassCastException错误
可通过instanceof判断类型
避免异常
if(i instanceof Dog){//判断i对象是不是狗类型的
((Dog)i).eat();
}
Java中基本数据类型的类型转换
boolean不参加转换
(char,byte,short)<int<long<float<double
小转大:自动转换
大转小:强制转换
抽象类和抽象方法(重点)
**以后父类应全改成抽象类**
抽象类和抽象方法的作用:
目的是为子类提供一个通用的模板
,子类可以在模板的基础上进行开发,先重写父类的抽象方法,然后可以扩展子类自己的内容。抽象类设计避免了子类设计的随意性,通过抽象类,子类的设计变得更加严格,进行某些程度上的限制。
抽象类考点:
抽象类不能创建对象
抽象类有构造器
(只供子类调用,顶级父类还是Object)非子类不能调用抽象父类的构造器
抽象类不能被final修饰
,因为final修饰的类没有子类
抽象方法考点:
一个类中,只要有抽象方法,这个类一定是抽象类
抽象类中可以没有抽象方法
子类必须重写父类里的抽象方法,若没重写全部抽象方法,那么子类必须改为抽象类
package com.jr.curriculum.demo2;
public abstract class Demo2 {
public void Demo2(){
System.out.println("抽象类的构造方法");
}
public abstract void test();//抽象方法,必须被子类重写
/*
【抽象类、抽象方法】
抽象类:在程序中父类对象没有创建的必要了,如何告诉开发者不再创建父类对象:
public 【abstract】 class 类名
说明:
1.抽象类不能创建对象
2.抽象类有构造器(只供子类调用,顶级父类还是Object)
3.非子类不能调用抽象父类的构造器
抽象方法:在程序中父类要求子类重写方法,
public 【abstract】 void test();
说明:
1.一个类中,只要有抽象方法,这个类一定是抽象类
2.抽象类中可以没有抽象方法
3.子类必须重写父类里的抽象方法,若没重写全部抽象方法,那么子类必须改为抽象类
*/
}
public abstract class Test1 extends Demo2{//没有重写父类的抽象方法,那么必须变成抽象类
}
public class Test2 extends Test1{
@Override
public void test() {//重写父类的抽象方法
System.out.println("子类重写父类的抽象方法");
}
}
final关键字(重点)
final修饰变量:
会变成常量
- 常量名应该全大写(规范)
- 常量应该声明同时赋值(规范)
- 常量存在常量池,相同信息不会重复存储
- final修饰的是基本类型,值不可修改。
- final修饰的是引用类型,地址不可修改,对象的属性值可改。
修饰方法:
不能被重写
修饰类:
不能被继承
(不能有子类)
看下面干货分享
public class Demo3 /*extends String不能有子类*/{
public static void main(String[] args) {
final int A = 123;
// A = 12;//不可再改值了
final Demo3 demo3 = new Demo3();
// demo3 = new Demo3();//不可再改地址了
}
final public void test(){//不能被子类重写
}
/*
【final关键字】:最终的
可修饰:属性、方法、类
1.修饰变量:会变成常量
1)常量名应该全大写(规范)
2)常量应该声明同时赋值(规范)
3)常量存在常量池,相同信息不会重复存储
4)final修饰的是基本类型,值不可修改。
final修饰的是引用类型,地址不可修改。
2.修饰方法:不能被重写
3.修饰类:不能被继承(不能有子类)
*/
}
接口(重点※)
接口的作用:
为了解决Java的继承单根性(单继承)
首先想到的是内部类,之后用接口解决
接口的定义:
具有共同行为的几组对象的集合叫接口
类的定义:具有相同属性和共同行为的一组对象的集合叫类
重点:抽象父类和接口的异同
接口的不同 | 抽象类的不同 |
---|---|
没有构造器 | 有构造器,但不能调用。 (默认带无参构造) |
接口关键字:interface | 抽象类关键字:abstract class |
一个类可以多实现接口 | 一个类只能单继承父类 |
定义的变量都是全局静态常量 | 可以定义常量和变量 |
共同点 |
---|
都不能实例化对象 。 |
都可以实现多态, 接口可以声明 接口 new 实现类(); |
都有抽象方法和非抽象方法, (接口在1.8版本以后,且要default修饰,public default void(){内容},允许重写) |
如果当前类没有实现(抽象类/接口)的所有抽象方法,那么这个类必须是抽象类。 |
下面干货分享
/**
*抽象父类:因为父类没有创建对象的必要
* 子类共有的行为和属性提取出来做抽象父类等子类实现
*/
public abstract class Door {
private double hight;
private double wide;
public abstract void open();
public abstract void close();
}
public class HouseDoor extends Door implements BellRings/*,可放多个接口*/{
@Override
public void rings() {//实现接口的方法
System.out.println("门铃响了");
}
@Override
public void open() {
System.out.println("房门打开");
}
@Override
public void close() {
System.out.println("房门关闭");
}
}
public interface BellRings {//门铃接口
void rings();
}
public class Demo4 {
public static void main(String[] args) {
}
/*
【接口】
1.作用:为了解决Java的继承单根性(单继承) 首先想到的是内部类,之后用接口解决
2.什么是接口:
接口:具有共同行为的几组对象的集合叫接口
类:具有相同属性和共同行为的一组对象的集合叫类
3.如何使用接口:
定义接口:public interface 接口名{}
实现接口:public class 类 interface 接口{}
举例子:门 方法:开、关、指纹解锁、密码解锁 共性的放在父抽象类,特性的放在接口
属性:高、宽、颜色
接口直接可以多实现,类直接只能单继承
【重点:抽象父类和接口的异同】
1.接口不能创建对象 因为没有构造器
抽象父类也不能创建对象 有构造器,但不能调用。
2.接口关键字:interface
抽象类关键字:abstract class
3.一个类只能单继承父类
一个类可以多实现接口
4.接口也可以实现多态
声明接口 new 实现类();
5.抽象父类中可以有抽象方法和非抽象方法
接口中可以有抽象方法和非抽象方法(1.8版本以后的,且要在方法前权限修饰符改为default,允许重写)
public default void(){内容} //允许重写
public static void(){内容} //不允许重写
*/
}
内部类(了解,能看懂源码即可)
概述:
一个类的内部又完整的嵌套了另一个类的结构,被嵌套的是内部类,嵌套其他类的叫外部类。
类的成员:
属性、方法、构造器、代码块、内部类
也是为了解决java 单根性。
局部内部类
位置:外部类的方法、代码块、构造器内
特点:
- 有类名
- 和正常类一样使用
- 只能用final修饰,相当于局部变量,作用域只在定义的方法、代码块、构造器里生效
- 在局部内部类的方法或代码块中可直接访问外部类的成员和方法(含私有)
- 外部类可直接实例化内部类对象,然后使用内部类的资源
- 其他外部类不能直接使用,可以通过外部类实例化内部类对象,然后使用内部类的资源
- 内部类和外部类重名则就近原则,内部类可使用外部类名.this.成员 访问
public class LocalInnerClass {
public static void main(String[] args) {
Test test = new Test();
test.aaa();//外部类的方法,该方法在下面实例化了局部内部类并调用bbb方法,局部内部类中的bbb方法又实例化了内部类的内部类并调用方法才进行的输出。
}
}
class Test {//外部类
private int i = 100;//外部类的私有成员
private void test(){
System.out.println("我是外部类的私有方法,可以被内部类调用");
}
public void aaa(){//外部类的方法
class Inner{//局部内部类,定义在外部类的方法或代码块里
public void bbb(){
System.out.println("我是内部类的方法,我调用内部类的内部类的方法");
class Inner2{//内部类的内部类
public void ccc(){
System.out.println("我是内部类的内部类的方法,外部类i的值为:"+i);//在内部类的方法或代码块中可直接访问外部类私有的成员和方法
test();
}
}
Inner2 inner2 = new Inner2();//不这样写外部类无法访问内部类
inner2.ccc();
}
}
Inner inner = new Inner();
inner.bbb();
}
}
匿名内部类
位置:外部类的方法、代码块、构造器内
特点:
-
无类名(系统分配的名字不能直接看到,名字是类名$n)
-
本质还是一个类
-
同时还可以看做是一个对象(看下面特点6)
-
只能添加访问修饰符,相当于局部变量,作用域只在定义的方法、代码块、构造器里生效
-
为了继承父类或实现接口时不用特意写一个类,减少代码量
(直接继承父类并实例化生成对象)(直接实现接口并实例化生成对象)<-可通过新对象接收
-
只用类里的方法,都不用新对象接收了,本身看成对象.方法即可
-
外部类可直接实例化内部类对象,然后使用内部类的资源
-
其他外部类不能直接使用,可以通过外部类实例化内部类对象,然后使用内部类的资源
-
内部类和外部类重名则就近原则,内部类可使用外部类名.this.成员 访问
声明方式:
父类或接口 名 new 父类或接口(参数列){
类体
}
;
public class AnonymousInnerClass {//匿名内部类使用
public static void main(String[] args) {
Test01 test01 = new Test01();
test01.aaa();//外部类的方法,方法里的匿名内部类实现了接口
}
}
class Test01 {//外部类
private int i = 100;//外部类的私有属性
private void test(){
System.out.println("我是外部类的私有方法,可以被内部类调用");
}
public void aaa(){//外部类的方法
//基于接口的匿名内部类
Inter inter = new Inter() {//直接实现接口并实例化生成对象,然后将对象赋给inter对象
@Override
public void inter() {//实现接口里的方法
System.out.println("我实现了接口里的inter方法");
test();
System.out.println("我还能用外部类的私有属性i="+i);
}
};
inter.inter();
//基于类的匿名内部类
/*OtherClass otherClass = new OtherClass("常"){//用新对象otherClass接收内部类实例化的对象
@Override
public void test1() {
System.out.println("\n重写了外部类的方法");
}
};
otherClass.test1();*/
new OtherClass("常"){//只用类里的方法,都不用对象接收了,本身看成对象.方法即可
@Override
public void test1() {
System.out.println("\n重写了外部类的方法");
}
}.test1();
}
}
interface Inter{//接口
public abstract void inter();//接口中抽象方法
}
class OtherClass{//其他外部类
public OtherClass(String str) {//其他外部类的有参构造器
System.out.println("其他外部类的构造器\t\t"+str);
}
public void test1(){//其他外部类的方法
System.out.println("其他外部类的方法");
}
}
实用场景:
当做实参直接传递,简洁高效(就是可能别人看不懂)
public class AnonymousTest {//匿名内部类使用场景
public static void main(String[] args) {
//当做实参直接传递,不用实现接口并创建对象了
test(new TestInter() {
@Override
public void show() {
System.out.println("重写接口里的show方法");
}
});
test(new TestInter() {//相当又写了个类,实现了接口的方法
@Override
public void show() {
System.out.println("我又重写接口里的show方法");
}
});
}
//静态方法,形参是接口类型
public static void test(TestInter testInter){
testInter.show();
}
}
interface TestInter{//接口
void show();
}
成员内部类
位置:属于外部类的一部分,和属性方法构造器并列的位置
特点:(看做一个成员)
- 没有statc修饰
- 在成员内部类的方法或代码块中可直接访问外部类的成员和方法(含私有)
- 外部类可直接实例化内部类对象,然后使用内部类的资源
- 其他外部类不能直接使用,可以通过外部类实例化内部类对象,然后使用内部类的资源
- 可以添加任意访问权限修饰符(public…)
- 作用域和外部其他成员一样,在整个外部类
public class MemberInnerClass {//成员内部类使用
public static void main(String[] args) {
Other other = new Other();
other.test();//1.通过外部类的test方法(方法里实例化成员内部类,调用方法)
Other other2 = new Other();
Other.Inner inner = other2.new Inner();//2.通过外部类实例化成员内部类
}
}
class Other{
private int i = 100;//外部类的私有属性
public String name = "常";
private void other(){//外部类的私有方法
System.out.println("我是外部类私有方法");
}
class Inner{//成员内部类,直接放在成员的位置!!
public void show(){//直接可以使用外部类的成员(包括私有的)
System.out.println("外部类的i="+i+",名字叫"+name);
other();//使用外部类私有的方法
}
}
public void test(){
Inner inner = new Inner();
inner.show();//使用成员内部类的方法
}
}
静态内部类
位置:属于外部类的一部分,和属性方法构造器并列的位置
特点:
- 有statc修饰
- 在成员内部类的方法或代码块中只能访问外部类的静态成员和方法(含私有),不能访问非静态成员
- 外部类和其他外部类能直接实例化内部类,然后使用内部类的资源(其他内部类通过外部类.内部类即可实例化对象,看下面代码)
- 可以添加任意访问权限修饰符(public…)
- 作用域和外部其他成员一样,在整个外部类
public class StaticInnerClass {
public static void main(String[] args) {
OtherClasses os = new OtherClasses();
os.other();//外部类里实例化内部类并调用方法了
OtherClasses.Inner inner = new OtherClasses.Inner();//直接通过外部类.内部类使用
inner.show();
}
}
class OtherClasses{//外部类
private int i = 100;//外部类的私有属性
private static String name = "常";
static class Inner{//静态内部类,放在外部类的成员位置,static修饰
public void show(){
System.out.println("外部类的静态成员:"+name);
}
}
public void other(){
Inner inner = new Inner();
inner.show();
}
}