面向对象包括三大特征:封装,继承,多态
封装机制
要点
封装的好处:
1、封装之后,对于那个事物来说,看不到这个事物比较复杂的那一面,只能看到该事物简单的那一面。复杂性封装,对外提供简单的操作入口。
照相机就是一个很好的封装的案例,照相机的实现原理非常复杂,但是对于使用照相机的人来说,操作起来是非常方便的是非常便捷的。
还有像电视机也是封装的,电视机内存实现非常复杂,但是对于使用者来说不需要关心内部的实现原理,只需要会操作遥控器就行。
2、封装之后才会形成真正的"对象”,真正的”独立体”
3、封装就意味着以后的程序可以重复使用。并且这个事物应该适应性比较强,在任何场合都可以使用。
4、封装之后,对于事物本身,提高了安全性。【安全级别高】
封装的步骤:
1、所有属性私有化,使用private关键字进行修饰,private表示私有的,修饰的所有数据只能在本类中访问。
2、对外提供简单的操作入口,也就是说以后外部程序要想访问属性,必须通过这些简单的入口进行访问:
对外提供两个公开的方法,分别是set方法和get方法
想修改属性,调用set方法
想读取属性,调用get方法
3、set方法的命名规范示例:
public void setAge (int a){
age = a;
}
4、get方法的命名规范示例:
public int getAge (){
return age;
}
5、get set函数和构造方法编译器都可以自动生成
代码示例
public class UserTest {
public static void main (String[] args) {
//创建User对象
User user =new User();
//age=18;
//编译报错,age属性私有化,在外部程序中不能直接访问
//修改后age属性非常的安全,但是有点太安全了。
//对于目前的程序来说,age属性彻底在外部访问不到了。
// System.out.println (user.age);
//修改
user.setAge(-100);//读取
System.out.println (user.getAge ());
}
}
public class User {
//属性私有化
private int age;
//set方法没有返回值,因为set方法只负责修改数据
/*
public void setAge (int age){
age = age;//java有就近原则,这里其实并没有给age属性赋值,这里的age都是局部变量age
*/
//setter
public void setAge (int a){
//编写业务逻辑代码进行安全控制
//age = a;
if(a<0|| a>150){
System.out.println("对不起,您提供的年龄不合法");
return;
}
//getter
public int getAge (){
return age;
}
继承机制
要点
关于java语言当中的继承:
1、维承是面向对象三大特征之一,三大特征分别是:封装、维承、多态
2、继承”基本“的作用是:代码复用。但是继承最"重要”的作用是:有了继承才有了以后"方法的覆盖"和"多态机制"。
3、继承语法格式:
[修饰符列表] class 类名 extends 父类名{
类体=属性+方法
}
4、java语言当中的继承只支持单继承,一个类不能同时继承很多类,只能继承一个类。在C++中支持多继承。
5、关于继承中的一些术语:
B类继承A类,其中:
A类称为:父类、基类、超类、superclass
B类称为:子类、派生类、subclass
6、在java语言当中子类继承父类都继承哪些数据呢?
私有的不支持继承
构造方法不支持继承
其他数据都可以继承
7、虽然java语言当中只支持单继承,但是一个类也可以间接继承其它类,例如:
C extends B{}
B extends A{}
A extends T{}
C直接继承B类,但是类间接继承T、A类。
8、java语言中假设一个类没有显示的继承任何类,该类默认继承JavaSE库当中提供的java.lang.Object类。java语言中任何一个类中都有Object类的特征。
实例
public class ExtendsTest {
//MyEclipse快捷键:查找类型【open Type】--> ctrl + shift +t
//MyEolipse快捷键:查找资源【open Resource】-->ctrl + shift + r
public static void main (String[] args) {
/*ExtendsTest et = new ExtendsTest();
String s = et.toString();//这里编译通过了,这说明可以调用toString方法,ExtendsPest类中有toString()方法,从Object类中继承过来的。
System.out.println(s);//com.bjpowernode.javase.test012.ExtendsTest@da6bf4
*/
CreditAccount act = new CreditAccount();
act.setActno( "act = 001");
act.setBalance (-1000.0);
act.setCredit(0.99);
System.out.println(act.getActno() + "," + act.getBalance () + "," + act.getCredit())
}
}
public class CreditAccount extends Account {
private double credit;
public CreditAccount (){
super();
}
public double getCredit(){
return credit;
}
public void setCredit (double credit) {
this.credit = credit;
}
}
public class Account {
private string actno;
private double balance;
public Account(){}
public Account(String actno,double balance) {
this.actno = actno;
this.balance = balance ;
}
public String getactno() {
return actno;
}
public void setActno (String actno){
this.actno = actno;
}
public double getBalance () {
return balance ;
}
public void setBalance (double balance) {
this.balance = balance;
}
}
关于方法覆盖
1、什么时候使用方法重写?
当父类中的方法已经无法满足当前子类的业务需求,子类有必要将父类中维承过来的方法进行重新编写,这个重新编写的过程称为方法重写/方法覆益。
2、什么条件满足之后方法会发生重写呢?【代码满足什么条件之后,就构成方法的覆盖呢?】
*方法重写发生在具有继承关系的父子类之间
*方法重写的时候:返回值类型相同,方法名相同,形参列表相同。方法重写的时候:访问权限不能更低,可以更高。
*方法重写的时候:抛出异常不能更多,可以更少。
3、建议方法重写的时候尽量复制粘贴,不要编写,容易出错,导致没有产生覆盖。
4、注意:
私有方法不能继承,所以不能覆盖。
构造方法不能继承,所以不能覆盖。
静态方法不存在覆盖。
覆盖只针对方法,不针对属性。
多态机制
要点
关于java语言当中的多态语法机制:
1、Animal、Cat、Bird三个类之间的关系:
Cat继承Aninal
Bird维承Animal
Cat和Bird之间没有任何继承关系
2、关于多态中涉及到的几个概念:
向上转型(upcasting)
子类型——>父类型
又被称为:自动类型转换。
向下转型(downcasting)
父类型——>子类型
又被称为:强制类型转换。【需要加强制类型转换符】
★需要记忆:
无论是向上转型还是向下转型,两种类型之间必须要有继承关系。
没有继承关系,程序是无法编译通过的。
多态在实际开发中的作用:
1、面向对象编程的核心:定义好类,然后将类实例化为对象,给一个环境驱使一下,让各个对象之间协作起来形成一个系统。
2、多态的作用是什么?
降低程序的耦合度,提高程序的扩展力。能使用多态尽量使用多态。
核心:面向抽象编程,尽量不要面向具体编程。
向上转型
实例一
public class Animal{
public void move(){
System.out.println("动物在移动")
}
}
//鸟儿类
public class Bird extends Animal{
//重写从父类中继承过来的方法
public void move(){
System.out.println ("鸟儿在飞翔!");
}
}
//猫类
public class cat extends Animal {
//重写父类中继承过来的方法
public void move(){
System.out.println ("猫在走猫步!");
}
//不是从父类中继承过来的方法
//这个方法是子类对象特有的行为【不是说所有的动物都能抓老鼠!】
public void catchMouse(
System.out.println(”猫抓老鼠!");
}
public class Test{
public static void main (String[] args){
//以前编写的程序
Animal al = new Animal();
al.move() ;
Cat c1 = new Cat();
c1.move();
cl.catchMouse();
Bird bl = new Bird();
b1.move();
/**
* 1、Animal和Cat之间存在继承关系,Animal是父类,Cat是子类
* 2、Cat is a Animal【合理的】
* 3、new Cat()创建的对象的类型是Cat, a2这个引用的数据类型是Animal,可见它们进行了类型转换:子类型转换成父类型,称为向上转型/upcasting,或者称为自动类型转换。
* 4、Java中允许这种语法:父类型引用指向子类型对象(向上转型)。
*/
//使用多态语法机制
Animal a2 =new Cat();
/***
*1、java程序永远都分为编译阶段和运行阶段。
*2、先分析编译阶段,再分析运行阶段,编译无法通过,根本是无法运行的。
*3、编译阶段编译器检查a2这个引用的数据类型为Animal,由于Animal.class字节码当中有move()方法,所以编译通过了。这个过程我们成为静态绑定,编译阶段绑定。
*只有静态绑定成功之后才有后续的运行。
*4、在程序运行阶段,JVM堆内存当中真实创建的对象是Cat对象,那么以下程序在运行阶段一定会调用Cat对象的move()方法,此时发生了程序的动杰绑定,运行阶段绑定。
*5、无论是Cat类有没有重写move方法,运行阶段一定调用的是Cat对象的move方法,因为底层真实对象就是Cat对象。
*6、父类型引用指向子类型对象这种机制导致程序存在编译阶段绑定和运行阶段绑定两种不同的形态/状态,这种机制可以成为一种多态语法机制。
*/
a2.move();
/**
*分祈以下程序为什么不能调用?
*因为编译阶段编译器检查到a2的类型是Anima1类型,从Animal.class字节码文件当中查找catchMouse方法,最终没有找到该方法,导致静态绑定失败,没有绑定成功,也就是说编译失败了。别谈运行了。
*/
//a2.catchMouse();
}
向下转型
要点
什么时候需要使用向下转型呢?
当调用的方法是子类型中特有的,在父类型当中不存在,必须进行向下转型。
实例
在test类中添加:
Cat c2 = (Cat) a2;
c2.catchMouse();
/*
long x = 100L;
int i = (int)x;
*/
类型转换异常
//父类型引用指向子类型对象【多态】
Animal a3 = new Bird();
/**
*1、以下程序编译是没有问题的,因为编译器检查到a3的数据类型是Animal,Animal和Cat之问存在继承关系,并且Animal是父类型,Cat是子类型,父类型转换成子类型叫做向下转型,语法合格。
*
*2、程序虽然编译通过了,但是程序在运行阶段会出现异常,因为JVM堆内存当中真实存在的对象是Bird类型,Bird对象无法转换成Cat对象,因为两种类型之间不存在任何继承关系,此时出现了著名的异常:
java.lang.ClassCastException
类型转换异常,这种异常总是在向下转型的时发生。
*/
//Cat c3 = (Cat) a3;
类型转换异常解决方法
1、向上转型只要编译通过,运行一定不会出问题:Animal a = new Cat();
2、向下转型编译通过,运行可能错误:Animal a3 = new Bird();Cat c3 =(Cat)a3;
3、怎么避免向下转型出现的ClassCastException呢?
使用instanceof运算符可以避免出现以上的异常。
4、instanceof运算符怎么用?
语法格式:
(引用instanceof数据类型名)
以上运算符的执行结果类型是布尔类型,结果可能是true/false
关于运算结果true/false:
假设:(a instanceof Animal)
true表示:a这个引用指向的对象是一个Animal类型。
false表示:a这个引用指向的对象不是个Animal类型。
5、Java规范中要求:在进行强制类型转换之前,建议采用instanceof运算符进行判新,避免ClassCastException异常的发生。这是一种编程好习惯
if(a3 instanceof Cat){ //a3是一个Cat类型的对象
Cat c3 = (Cat)a3;
//调用子类对象中特有的方法
c3.catchMouse();
}else if(a3 instanceof Bird){ //a3是一个Bi.rd类型的对象
Bird b2 = (Bird)a3;
b2.fly();
}