网站首页 > java教程 正文
1、封装
1.1 定义
隐藏对象内部的属性和实现细节,仅对外公开接口来和对象进行交互。
例如对于电脑这样一个复杂的设备,提供给用户的就只是:开关机、通过键盘输入,显示器,USB插孔等,让用户来和计算机进行交互,完成日常事务。但实际上电脑真正工作的却是CPU、显卡、内存等一些硬件元件,而这些元件并不直接对用户开放。
1.2 作用
- 不需要关注对象内部细节,只需关注对象暴露出来的接口,简化和对象交互
- 只能通过对象暴露出的接口,进行对对象的访问,规范了对象访问的方式
- 对对象内部数据结构进行保护
1.3 Java封装的实现
Java中主要通过类和权限修饰符来实现封装,类可以将数据和操作数据的方法结合在一起,更符合人类对事物的认知,权限修饰符用来控制,外部对类内部数据的访问。
权限范围:
权限使用:
- 类只能被public和default进行修饰
- 类的成员变量和成员方法可以被public、protected、default、private进行修饰
【注】当父类和子类不在同一个包内,子类对于父类内被protected修饰的成员,只能通过super进行访问。
2、继承
2.1 定义
抽取对多个类的共同属性和行为到某个类,其他的类进行继承,可以实现对这些属性和行为的复用,无需重复定义。如果子类需要扩展可以重写父类方法,或者添加新的属性和方法。
2.2 作用
代码的复用
2.3 继承实现
通用extends关键字进行继承
public class Animal{
protected String name;
protected void eat(){
}
}
/**
* Dog继承了Animal的name和eat()
*/
public class Dog extends Animal{
protected String name;
protected void eat(){
}
}
【注】
- 子类会将父类中的成员变量或者成员方法继承到子类中去
- 子类继承父类之后,必须要新添加自己特有的成员,体现出与基类的不同,否则就没有必要继承了
2.4 继承原则说明
2.4.1 构造器调用
调用子类构造方法产生子类对象之前,默认调用父类的构造方法先产生父类对象而后产生子类对象
2.4.2 Java中的单继承局限
Java中不允许多重继承,但允许多层继承
Java中一个类只能使用extends继承一个父类,不能同时extends继承多个父类
如下继承语法时错误
public class A{}
public class B{}
//这种语法时错误的
public class C extends A,B{}
2.4.3 super关键字
2.4.3.1 super访问属性
super.属性名 访问的时父类的属性
1)当子类有属性和父类同名时,访问的是子类属性,输出的是子类属性值
public class Parent {
protected String name = "爸爸";
}
class Son extends Parent{
protected String name="儿子";
public void printInfo(){
System.out.println(super.name); //输出“爸爸”
System.out.println(name); //输出“儿子”
}
public static void main(String[] args) {
Son son = new Son();
son.printInfo();
}
}
输出结果如下图:
2)当子类没有属性和父类同名时,访问的是父类的属性,输出的是父类属性值
public class Parent {
protected String name = "爸爸";
}
class Son extends Parent{
//protected String name="儿子"; //注释掉看输出的效果
public void printInfo(){
System.out.println(super.name); //输出“爸爸”
System.out.println(name); //也是输出“爸爸”
}
public static void main(String[] args) {
Son son = new Son();
son.printInfo();
}
}
输出结果如下图:
2.4.3.2 super调用构造器
1)父类有默认的无参构造器,子类构造器会默认去调用父类的无参构造器
public class Parent {
public Parent(){
System.out.println("爸爸1");
}
public Parent(String name){
System.out.println(name);
}
}
class Son extends Parent{
public Son(){
System.out.println("儿子");
}
public static void main(String[] args) {
Son son = new Son();
}
}
输出结果如下图:
2)父类没有默认的无参构造器,子类构造器需要手动去调用父类的其他构造器
父类注释默认无参构造器后报错:
父类注释掉默认的无参构造器后,子类构造器内部去调用父类其他构造器,编译通过
2.4.3.3 super访问普通方法
super访问普通方法,逻辑同访问属性一致,这里不再赘述,可参考2.4.3.1
2.4.3.4 总结
- this表示当前对象的成员变量或方法的调用
- super表示父类对象的成员变量与方法的调用
- 当父类中不存在无参构造,则子类构造方法的首行必须使用super(参数)显式调用父类中的有参构造。
2.5 final
1)修饰变量或字段,表示常量(即不能修改)
final int a = 10;
a = 20; // 编译出错
2)修饰类表示此类不能被继承
final public class Animal {
...
}
public class Bird extends Animal {
...
}
// 编译出错
Error:(3, 27) java: 无法从最终com.bit.Animal进行继承
我们平时使用的 String 字符串类, 就是用 final 修饰的, 不能被继承
3)修饰方法,表示方法不能被重写
3、多态
3.1 定义
当同一种类型的对象,去做同一种行为的时候,所体现的效果不同。
例如打印机有彩色打印机和黑白打印机,它们都有”打印文件“的行为,但是打印的文件颜色效果不同,这就是多态的一种体现。
3.2 多态的条件
- 必须发生继承
- 子类要重写父类方法
- 通过父类的引用调用重写的方法
多态在代码中体现
/**
* 打印机
*/
public abstract class Printer {
protected void print(){
System.out.println("打印出未知颜色的文件");
}
}
/**
* 黑白打印机
*/
class BlackWhitePrinter extends Printer{
@Override
protected void print() {
System.out.println("打印出黑白的文件");
}
}
/**
* 彩色打印机
*/
class ColorfulPrinter extends Printer{
@Override
protected void print() {
System.out.println("打印出彩色的文件");
}
}
class Runner{
public static void main(String[] args) {
Printer pr1 = new BlackWhitePrinter();
Printer pr2 = new ColorfulPrinter();
//pr1和pr2都是用Printer类型的引用进行引用,打印出效果不同,体现了多态。
pr1.print();
pr2.print();
}
}
上述代码,基类为Printer,BlackWhitePrinter和ColorfulPrinter都继承了Printer,并重写了Printer的print(),调用的时候,BlackWhitePrinter和ColorfulPrinter的对象都是用Printer类型的变量进行引用,调用了同一个方法,但是产生的效果不同,这是多态的体现。
输出结果如下:
3.3 重写
3.3.1 重写的定义
- 重写是子类对父类非静态、非private修饰,非final修饰,非构造方法等的实现过程 进行重新编写, 返回值和形参都不能改变
- 重写的好处在于子类可以根据需要,定义特定 于自己的行为。 也就是说子类能够根据需要实现父类的方法。
3.3.2重写的规则
- 子类在重写父类的方法时,一般必须与父类方法原型一致: 返回值类型 方法名 (参数列表) 要完全一致
- 被重写的方法返回值类型可以不同,但是必须是具有父子关系的
- 访问权限不能比父类中被重写的方法的访问权限更低。例如:如果父类方法被public修饰,则子类中重写该方 法就不能声明为 protected
- 父类被static、private修饰的方法、构造方法都不能被重写。
- 重写的方法, 可以使用 @Override 注解来显式指定. 有了这个注解能帮我们进行一些合法性校验. 例如不小心 将方法名字拼写错了 (比如写成 aet), 那么此时编译器就会发现父类中没有 aet 方法, 就会编译报错, 提示无法 构成重写.
3.3.3重写和重载的区别
3.4 向上和向下转型
3.4.1 向上转型
定义
向上转型:实际就是创建一个子类对象,将其当成父类对象来使用。
语法格式:父类类型 对象名 = new 子类类型()
Animal animal = new Cat("元宝",2);
使用场景
- 直接赋值
- 方法传参
- 方法返回
public class TestAnimal {
// 2. 方法传参:形参为父类型引用,可以接收任意子类的对象
public static void eatFood(Animal a){
a.eat();
}
// 3. 作返回值:返回任意子类对象
public static Animal buyAnimal(String var){
if("狗".equals(var) ){
return new Dog("狗狗",1);
}else if("猫" .equals(var)){
return new Cat("猫猫", 1);
}else{
return null;
}
}
public static void main(String[] args) {
Animal cat = new Cat("元宝",2); // 1. 直接赋值:子类对象赋值给父类对象
Dog dog = new Dog("小七", 1);
eatFood(cat);
eatFood(dog);
Animal animal = buyAnimal("狗");
animal.eat();
animal = buyAnimal("猫");
animal.eat();
}
}
【注】
- 向上转型的优点:让代码实现更简单灵活。
- 向上转型的缺陷:不能调用到子类特有的方法。
3.4.2 向下转型
将一个子类对象经过向上转型之后当成父类方法使用,再无法调用子类的方法,但有时候可能需要调用子类特有的 方法,此时:将父类引用再还原为子类对象即可,即向下转换.
public class TestAnimal {
public static void main(String[] args) {
Cat cat = new Cat();
Dog dog = new Dog();
Animal animal = cat; //向上转型
animal.eat(); //输出“cat eat",当前实际类型为Cat
animal = dog; //指向dog对象
animal.eat(); //输出“dog eat",,当前实际类型为Dog
// cat = (Cat)animal; //animal类型为Animal,实际类型为Dog,向下转型为Cat,虽然编译通过,但是运行时报错
// cat.mew();
dog = (Dog)animal; //animal引用类型为Animal,实际类型为Dog,向下转型为Dog,编译通过,运行也能通过
dog.bark();
}
}
class Animal{
protected void eat(){};
}
class Cat extends Animal{
@Override
protected void eat() {
System.out.println("cat eat");
}
public void mew(){
System.out.println("喵喵");
}
}
class Dog extends Animal{
@Override
protected void eat() {
System.out.println("dog eat");
}
public void bark(){
System.out.println("汪汪");
}
}
向下转型用的比较少,而且不安全,万一转换失败,运行时就会抛异常。Java中为了提高向下转型的安全性,引入 了 instanceof ,如果该表达式为true,则可以安全转换。
public class TestAnimal {
public static void main(String[] args) {
Cat cat = new Cat();
Dog dog = new Dog();
Animal animal = cat; //向上转型
animal.eat(); //输出“cat eat",引用类型为Animal,当前实际类型为Cat
animal = dog; //指向dog对象
animal.eat(); //输出“dog eat",引用类型为Animal,当前实际类型为Dog
if (animal instanceof Cat) { //判断实际类型是否为Cat
cat = (Cat)animal;
cat.mew();
}
if (animal instanceof Dog) { //判断实际类型是否为Dog
dog = (Dog)animal;
dog.bark();
}
}
}
class Animal{
protected void eat(){};
}
class Cat extends Animal{
@Override
protected void eat() {
System.out.println("cat eat");
}
public void mew(){
System.out.println("喵喵");
}
}
class Dog extends Animal{
@Override
protected void eat() {
System.out.println("dog eat");
}
public void bark(){
System.out.println("汪汪");
}
}
猜你喜欢
- 2024-10-07 java 面对对象的三大特性——面试的时候一直在看,面试官很满意
- 2024-10-07 第三章 java内存模型与并发三大特性
- 2024-10-07 理解Java的三大特性之封装(java的封装是什么)
- 2024-10-07 揭秘Java五大特性,你不容错过!(java的基本特性)
- 2024-10-07 JAVA基础——面向对象三大特性:封装、继承、多态
- 2024-10-07 Java有哪些特性?(请简述java有哪些特性)
- 2024-10-07 Java-面向对象三大基本特性,五大基本原则
- 2024-10-07 java多线程中的三大特性用代码给大家解释清楚
- 2024-10-07 好程序员Java学习路线分享三大特性之多态
- 2024-10-07 Java 12 新特性概述(java语言具有较好的安全性和可移植性及与平台无关等特性)
你 发表评论:
欢迎- 最近发表
- 标签列表
-
- java反编译工具 (77)
- java反射 (57)
- java接口 (61)
- java随机数 (63)
- java7下载 (59)
- java数据结构 (61)
- java 三目运算符 (65)
- java对象转map (63)
- Java继承 (69)
- java字符串替换 (60)
- 快速排序java (59)
- java并发编程 (58)
- java api文档 (60)
- centos安装java (57)
- java调用webservice接口 (61)
- java深拷贝 (61)
- 工厂模式java (59)
- java代理模式 (59)
- java.lang (57)
- java连接mysql数据库 (67)
- java重载 (68)
- java 循环语句 (66)
- java反序列化 (58)
- java时间函数 (60)
- java是值传递还是引用传递 (62)
本文暂时没有评论,来添加一个吧(●'◡'●)