类似于现实中看电视,我们要换台时只需要通过遥控器这个接口就能实现,而不需要知道电视的内部结构完成了什么步骤,这就是封装。
高内聚,低耦合:内部细节数据由自己完成,不让外部干涉;仅暴露部分方法给外部使用
将属性私有,通过get、set方法来设置和显示属性值:
set()方法中可以设置一些报错信息
封装的作用:
父类 (基类) 子类(派生类)是父类的抽象 ,通过extends关键词可以继承父类。有子类is a 父类的关系。
子类是对父类的扩展,子类可以继承父类的所有public属性和方法。(但是不能继承private的属性和方法,一般属性被封装为private,而方法一般为public权限,所有可以通过Get,Set方法来使子类调用父类的属性)
权限:
public 公开的
protected 保护的
default 默认的
private 私有的
注意:
一个子类只能有一个父类,而一个父类可以有多个子类。
单继承就是:子类的父类可能还有它的父类,但是这个“爷爷类”不能算是子类的夫类
重点:
object类:
JAVAZ中所有的类直接间接继承boject,包含以下等方法:
super:调用出父类的属性.方法
第一个name打印的 是形参, 第二个this.name打印的是子类的name,第三个super打印的父类的name属性。
当子类继承了父类,但是在子类中进行了方法重写后,调用时用的是子类的方法。
构造器:
1.new一个 子类时 会先调用父类的构造器,再调用子类的构造器
2.用this和super调用构造器时,必须放在子类构造器的第一行
3.当父类定义了有参构造后,无参构造会自动消失。因为new一个子类时会先调用父类的无参构造器(不管子类是有参还是无参),再调用子类的构造器。如果父类只有有参构造器而没有无参构造器子类就会报错。(除非子类的第一行就用super调用父类的有参构造器)
所以通常在写类时如果定义了有参构造,就要另外再显示构造一个无参构造器。这样当他作为父类时就不会报错。
子类为无参:
结果:
子类为有参:
结果:
super注意点总结:
方法重写 @Override
*重点总结:
1.重写需要有继承关系,且是子类对父类的方法重写。
重写时子类的方法和父类必须一致(方法名相同、参数列表相同)不同的只是方法体
2.静态方法的调用只和左边定义的数据类型有关,只有非静态的方法才能重写
3.修饰符:范围可以扩大: public>protected>default>private
4.抛出的异常:范围可以被缩小,但不能扩大:ClassNotFoundException -->Excertion(大)
为什么要重写?
父类的功能子类不一定需要,或者不一定满足(需要更多)。
静态的方法:调用只和左边定义的数据类型有关
因为类中的静态方法只属于类,不能重写。(final 常量、private 私有类型方法也不能重写)
如下:
A是子类 B是父类,
A a =new A(); a.text();方法调用的是A类test()方法的方法
B b = new A();//父类的引用指向的子类 ,此时b 调用的是B类的test(方法)
非静态的方法(只有非静态的方法才能重写)
A a =new A(); new了一个A(),指向的是A类的一个实例a.
B b = new A();//父类的引用指向的子类 , new了一个A(),指向的是B的实例 b,但是还是A,这就是子类重写了父类的方法
多态本身就是向上转型过的过程
使用格式:父类类型 变量名=new 子类类型();
适用场景:当不需要面对子类类型时,通过提高扩展性,或者使用父类的功能就能完成相应的操作。
必须先向上转型才能向上转型,将父类引用类型转为子类引用各类型
使用格式:子类类型 变量名=(子类类型) 父类类型的变量;
适用场景:当要使用子类特有功能时。
多态是什么?
多态: 事物存在的多种形态
对象存在的多种形态
多态是什么多态? 多态是对象的多态,方法的多态是对象多态的体现
(代码层面)对象存在的多种类型
Cat c = new Cat(); //对象是 猫 类
Animal a = new Cat(); //对象是 动物 类
同一方法可以根据发送对象的不同而采用多种不同的行为方式
例子①:
猫类(继承动物类):
1.猫继承与动物
2.猫类中重写了父类的run()方法
然后写了一个测试类:
其中Animal a = new Cat(); //向上转型(Animal在栈中的引用a 指向了new出来的Cat()对象,此时是不能调用子类cat中特有的属性与方法的!!!)
满足了多态的第三个条件:3.父类的引用指向了子类
结果:
子类Cat重写了父类的Animal的非静态方法eat();输出结果为:猫在吃饭
子类Cat重写了父类的Animal的静态方法sleep();输出结果为:动物在睡觉
未被子类(Cat)重写的父类(Animal)方法run();输出结果为:动物在跑
然而 a不能调用子类中特有的属性与方法:a.catchMouse()在编译时就报错了
这是多态的缺点,可以这么理解:对象a 实际上是Cat类的,但是父类Animal的引用指向了a,它乔装成了Animal类(此时他是A类但是他有随时可以变回C类)。因为乔装了不能被发现所一a只能
有父类Animal的属性与方法,而不能有C类的属性与方法(实际上是因为父亲的类型,智能看到堆内存中super的一小块空间)。
如果a想用Cat中的catchMouse()方法就必须放弃乔装从Animal类———>强制转化为Cat类。
就能调用catchMouse()方法:
代码:
结果:
向下转型注意点:
1. 向下转型,必须发生在子父类的关系当中
2. 向下转型之前,必须得先有向上转型。转上去,才能转下来
Animal a = new Animal();Dog d = (Dog) a ;//报错
例:
Animal a = new Dog();//对象dog()向上转型为父类Animal
Dog d = (Dog) a ; //向下转型 ,不报错
Cat c = (Cat) a ;//报错
狗类和猫类不存在子父类关系.
ClassCastException :类型转换异常产生:当引用数据类型的强转,出现了错误就会抛出此异常
例子②:
public class TestSuperMan{
public static void main (String [] args) {
//1. 超人乔装成人
Person p =new SuperMan();//向上转型(父类引用指向子类引用,此时不能调用子类的属性和行为)
//多态创建对象,并调用成员变量的特点(编译看左边,运行看左边)
System.out.println(p.name);// 克拉克
//2.谈生意
p.谈生意();
//这时有人跳楼,超人要去救人,
p.fly(); //报错,因为乔装成人了
//多态的弊端:不能调用子类特有的属性和行为
//需要向下转型,将乔装成人的[超人]-->转换为超人类型
SuperMan sm = (SuperMan) p ;//向下转型
//3.飞出去救人
System.out.println(sm.name);
sm.fly();
}
}
class Person {
String name = "克拉克";
public void 谈生意 () {
System.out.println("谈几个亿的大单子");
}
}
class SuperMan extends Person {
String name = "超人";
public void fly () {
System.out.println("飞出去救人"");
}
}
例子③
用花木兰替父从军的例子来理解多态:
花木兰替父亲花弧从军。那么这时候花木兰是子类,花弧是父类。花弧有自己的成员属性年龄,姓名,性别。花木兰也有这些属性,但是很明显二者的属性完全不一样。花弧有自己的非静态成员方法‘骑马杀敌’,同样花木兰也遗传了父亲一样的方法‘骑马杀敌’。花弧还有一个静态方法‘自我介绍’,每个人都可以问花弧姓甚名谁。同时花木兰还有一个自己特有的非静态成员方法‘涂脂抹粉’。但是,现在花木兰替父从军,女扮男装。这时候相当于父类的引用(花弧这个名字)指向了子类对象(花木兰这个人),那么在其他类(其他的人)中访问子类对象(花木兰这个人)的成员属性(姓名,年龄,性别)时,其实看到的都是花木兰她父亲的名字(花弧)、年龄(60岁)、性别(男)。当访问子类对象(花木兰这个人)的非静态成员方法(骑马打仗)时,其实都是看到花木兰自己运用十八般武艺在骑马打仗。当访问花木兰的静态方法时(自我介绍),花木兰自己都是用她父亲的名字信息在向别人作自我介绍。并且这时候花木兰不能使用自己特有的成员方法‘涂脂抹粉’。-----多态中的向上转型
终于一将功成万骨枯,打仗旗开得胜了,花木兰告别了战争生活。有一天,遇到了自己心爱的男人,这时候爱情的力量将父类对象的引用(花弧这个名字)强制转换为子类对象本来的引用(花木兰这个名字),那么花木兰又从新成为了她自己,这时候她完全是她自己了。名字是花木兰,年龄是28,性别是女,打仗依然那样生猛女汉子,自我介绍则堂堂正正地告诉别人我叫花木兰。OMG!终于,终于可以使用自己特有的成员方法‘涂脂抹粉’了。从此,花木兰完全回到了替父从军前的那个花木兰了。并且和自己心爱的男人幸福的过完了一生。-----多态中的向下转型。
PS:向上转型向下转型一定是在多态这个前提下,否则强制将女儿变成父亲,或者将父亲变成女人,就变成东方不败了,系统此时就会报错非法类型转换。哈哈哈哈哈。另外开发中一般是利用多态声明形式参数,并将创建子类的匿名对象作为实际参数。以上。
(参考知乎回答:小史的JavaSE课堂随笔整理)
根据以上情况总结多态创建对象时,调用成员变量和方法时的特点:
①成员变量(属性):编译看左边(父类),运行看左边(父类)
多态是方法的多态,属性没有多态
②成员方法:编译看左边(父类),运行看右边(子类)动态绑定
编译时会检查父类中是否存在该方法[也叫动态绑定机制]
如果不存在,编译阶段直接报错
如果存在, 编译通过,但是运行时,执行子类的方法(因为部分方法在父类中,是不存在方法体逻辑的如果运行时走父类的方法,那么没有逻辑就没有意义)
Animal a = new Cat();
Cat b = new Cat();
比较a和b:
a只能使用父类的所有方法或者子类中重写了的父类的方法(编译看左边)而不能使用子类中特有的属性与方法。 其中静态方法和没有重写的非静态方法 调用的是父类方法,重写了的方法 最终调用的是子类的方法(运行看右边)。
而b既可以使用父类Animal的所有方法,也可以使用子类Cat的所有方法
③静态方法:编译看左边(父类),运行看左边(父类)
因为类中的静态方法只属于类,不能重写。(final 常量、private 私有类型方法也不能重写)
多态的缺点:
多态后不能调用子类的的特有的成员属相和子类特有的成员方法
多态的优点:
1.提高了代码的复用性
2.提高了代码的维护性
3.提高了代码的扩展性:可以将一个方法的形式参数,定义为父亲类型,该方法就能接受这个父类的任意子类对象
实际开发的过程中,父类类型作为方法形式参数,传递子类对象给方法,进行方法的调用 ,更能体现出多态的拓展性与便利,
4.方便方法的调用时,减少重复的代码!简洁。
在使用有继承关系的类方法时,不用重新new一个类,而是把一个类向上转型或者向下转型就可以用其他类的方法了。
instenceof关键字用于判判定某对象是否为特定类(或者该特定类的子类/父类)若是则 为true;反之 则为false
System.out.println(X instanceof Y);编译能否通过,取决于X与Y是否有父子关系
例:有下面三个继承关系
①:
object默认是Object类(但实际上是隐式的Student类),
有继承关系:
结果:
②:
person默认是Person类(但实际上是隐式的Student类)
有继承关系
而Sring类既和Student与Person类都没有父子关系,所以编译不通过。
结果:
③:
student有继承关系:Object>Person>Student
student类与teacher类和string类没有父子关系所以编译报错了
结果:
类型之间的转换:
父类的引用可以指向子类//向上转型,向上转型的子类可以强制转化为子类//向下转型
Person obj = new Student();//向上转型,不用强制转换直接完成
obj默认是Person类(但实际是隐式的Student类),obj不能直接调用 子类Student中独有的属性与方法,必须要将其向下转型为Student类。
有以下继承关系:
obj可以向下转型为Person类或Student类???吗
向下转型注意点:
需要用强制转换:格式:((子类)父类对象)
1. 向下转型,必须发生在子父类的关系当中
2. 向下转型之前,必须得先有向上转型。转上去,才能转下来
Animal a = new Animal();Dog d = (Dog) a ;//报错
ClassCastException :类型转换异常产生:当引用数据类型的强转,出现了错误就会抛出此异常
静态变量/方法 可以直接通过 类名.属性/方法名调用。
而非静态变量 需要先new一个实例,然后再实例名.属性/方法名。
方法和类中有静态代码块和匿名代码块,会在构造方法之前加载。
PS:1.静态代码块和类一起加载(最先加载),且只执行一次
2.可以用匿名代码块附初始值
1.abstract修饰符可以用来修饰方法和类,抽象类里可以没有抽象方法,但是有抽象方法的一定是抽象类。(抽象类中可以有普通的方法,即有方法体的方法)
2.抽象类:不能使用new关键词来创建对象,它是用来让子类继承的。约束!
3.抽象方法,只有方法的声明,没有方法的实现,它是用来让子类实现的
4.子类继承抽象类,那么子类必须要实现抽象类没有实现的抽象方法,否则该子类也要声明为抽象类
抽象类是单继承~ 而接口可以多继承~
有构造器;
抽象类意义:
例如游戏角色,将其公有属性抽象出来放在抽象类中。每个角色在继承抽象类时另外的增删其独有的属性和方法。提高开发效率和可扩展性
普通类、抽象类、接口的区别:
①:
普通类:只有方法的具体实现
抽象类:具体实现方法和抽象方法(规范)都有
接口:只有规范!自己无法写
②:普通类和抽象类关键词为:class
接口的本质是契约,对象的抽象是OO的精髓,而接口是最能体现抽象的。
定义了两个接口:UserService和TimerService
1.接口中定义的属性都默认带有修饰词:public static final
2.接口中的定义方法默认都带有修饰词:public abstract
3.接口中的方法不能定义,由其子类在继承时实现(重写override)
定义了一个实现接口的类:UserServiceimpl
1. 类可以实现接口
抽象类的关键词:extends
接口 的关键词:implments
2.实现接口的类必须实现接口中的抽象方法
和抽象类一样,接口在被实现时,实现接口的类必须实现接口中的抽象方法。
3.利用接口可以实现多继承!
作用:
1.约束(接口中不能实现,让别人来进行实现)
2.定义一些方法,让不同的人实现 ~ n---->1
总结及注意点:
1.接口中定义的属性都默认带有修饰词:public static final
2.接口中的定义方法默认都带有修饰词:public abstract
3.接口中没有构造方法~故而接口不能被实例化~
4.实现类中的implments关键词后面可以实现多个接口(变相的多继承)
5.实现接口的类必须要实现(重写)接口中的抽象方法
1.成员内部类
2.静态内部类
里面不能调用 外部类的私有非静态属性,因为静态属性是和类一起最先加载的
3.局部内部类
4.匿名内部类
//没有名字初始化类,不用将实例保存到变量中
//一个java文件中可以有多个class类,但是只能有一个public class