面向对象的三大特征:封装、继承、多态
封装
封装的好处:
1.封装之后,对于那个事物来说,看不到比较复杂的一面,只看得到简单的一面,复杂的封装性,对外提供简单的操作入口; eg:照相机、电视机
2.封装之后才会形成真正的对象,真正的独立体
3.封装意味着可以重复使用,并且这个事物适应性比较强,在任何场合都可以使用;
4.封装之后对于事物本身提高了安全性
首先看一道例题
/*
* 用户类
*/
public class User {
int age;
String name;
}
public class UserTest {
public static void main(String[] args) {
//创建User对象
User user = new User();
//访问age
//读取年龄值【get】
System.out.println(user.age);
//修改年龄值【set】
user.age = 20;
//格式化快捷键:ctrl+shift+f
System.out.println(user.age);
user.age =-2;
System.out.println(user.age);
//这里的age属性是完全暴露给外部程序的,
}
}
user的年龄可以随意访问,可以随意修改,对于一个用户年龄不可能为负数,但以下程序可以运行,这是当前程序存在的缺陷
面对该缺陷,我们提出封装来解决这个问题
封装的步骤:
1.所有属性私有化,使用private关键字进行修饰,private表示私有化
-
2.对外提供简单的操作入口,也就是说以后外部程序想要访问age属性,必须通过这些入口进行访问。修饰的所有数据只能在本类中访问
-
-两种公开的方法,分别是 set方法和get方法
-
-想修改age属性,调用set方法
-
-想读取age属性,调用get方法
3.set方法的命名规范:
public void set + 属性名(首字母大写)(形参){ }
public void setAge(int a){
age = a
}
4.get方法的命名规范:
public int getAge(){
return age;
}
- *注意:
setter and getter 方法没有 static 关键字
有static关键字怎么调用:类名.方法名(实参);
没有static关键字怎么调用:引用.方法名(实参);
一个属性通常访问时包括几种形式?
- -第一种:想要读取这个属性时,读取get;
- -第二种:想要修改这个属性时,修改set;
修改上述程序
public class User1 {
private int age;
//set方法没有返回值因为set方法只负责修改数据
public void setAge(int a) {
if(a<0||a>150) {
System.out.println("对不起,您的年龄不合法!");
return;
}
age = a;
}
public int getAge() {
return age;
}
}
public class UserTest1 {
public static void main(String[] args) {
User1 u = new User1();
//编译报错,对于目前程序
//System.out.println(u.age); 无法访问到【age属性被封装】
//修改
u.setAge(-100);
System.out.println(u.getAge());
u.setAge(110);
System.out.println(u.getAge());
}
}
例2:
/*
* 快捷方法创建 set和get
* source里边 Generate setter and getter
*/
//顾客类
public class Custumer {
//属性
private int id;
private int age;
private String name;
private String addr;
//setter and getter 方法
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAddr() {
return addr;
}
public void setAddr(String addr) {
this.addr = addr;
}
}
public class CustumerTest {
public static void main(String[] args) {
Custumer c =new Custumer();
c.setId(11444);
c.setName("ya蛋");
c.setAge(22);
c.setAddr("北京田汉怕");
System.out.println(c.getName());
System.out.println(c.getAge());
System.out.println(c.getId());
System.out.println(c.getAddr());
}
}
继承
继承:
-是面向对象三大特征之一
-作用:基本作用:代码复用,"重要"作用:但是有了继承才有了方法的覆盖和多态机制
1.语法格式:
[修饰符列表]class 类名 extends 父类名{
类名 = 属性 + 方法
}
2.Java中的继承只支持单继承,一个类不能同时继承很多类,只能继承一类,在C++中支持多继承
3.关于java中继承的一些术语:
B类继承A类:
A类称为:父类、基类、超类、superclass
B类称为:字类、派生类、subclass
4.在Java中子类继承父类,都继承哪些东西呢?
-私有的不支持继承
-构造方法不支持继承
-其他数据都可以被继承
5.虽然Java语言当中只支持单继承,但是一个类也可以间接继承其他类,例如:
C extends B{
}
B extends A{
}
A extends T{
}
C直接继承A,但是间接继承B\A\T
6.Java语言当中假设一个类没有显示继承任何类,该类默认继承javase当中提供的java.lang.Object类。
Java语言任何一个类都有Object类的特征
账户类
/*
* 账户
*/
public class Account0 {
private String sno;
private double balance;
public Account0() {
super();
}
public Account0(String sno, double balance) {
super();
this.sno = sno;
this.balance = balance;
}
public String getName() {
return sno;
}
public void setName(String name) {
this.sno = name;
}
public double getBalance() {
return balance;
}
public void setBalance(double balance) {
this.balance = balance;
}
}
未继承的信用账户类
/*
* 信用账户
* balance
*/
public class CreditAccount {
private String sno;
private double balance;
private double credit;
public CreditAccount() {
super();
}
public CreditAccount(String sno, double balance, double credit) {
super();
this.sno = sno;
this.balance = balance;
this.credit = credit;
}
public String getSno() {
return sno;
}
public void setSno(String sno) {
this.sno = sno;
}
public double getBalance() {
return balance;
}
public void setBalance(double balance) {
this.balance = balance;
}
public double getCredit() {
return credit;
}
public void setCredit(double credit) {
this.credit = credit;
}
}
使用继承的信用账户类
public class CreditAccount0 extends Account0 {
private double credit;
public CreditAccount0() {
super();
}
public CreditAccount0( double credit) {
super();
this.credit = credit;
}
public double getCredit() {
return credit;
}
public void setCredit(double credit) {
this.credit = credit;
}
}
测试:
public class ExtendsTest {
//快捷键:查找类型--> ctrl + shift + t
public static void main(String[] args) {
ExtendsTest s = new ExtendsTest();
String e = s.toString(); //Object类继承过来的
System.out.println(e);
CreditAccount0 m = new CreditAccount0();
m.setBalance(-1000);
System.out.println(m.getBalance());
}
}
例2:
public class ExtendsTest01 {
public static void main(String[] args) {
C c = new C();
c.doSome();
}
}
class A{
public void doSome() {
System.out.println(121212121);
}
}
class B extends A{
public void doSome2() {
System.out.println(787878);
}
}
class C extends B{
}
多态
关于Java语言当中多态的语法机制:
1.Animal、Cat、Bird之间的关系:
Cat、Bird 继承 Animal
Cat、Bird之间没有继承关系
2.多态涉及到的几个概念:
-向上转型(upcasting)
-子类型转换成父类型(自动类型转化)
-向下转型(downcasting)
-父类—>子类 (需要强制类型转化符 extends)
什么时候需要使用向下转型?
当调用的方法是子类中特有的,在父类中不存在。
3.多态的实现前提:有继承或者实现关系;有方法重写;有父(类/接口)引用指向(子/实现)类对象。
4.多态的形式:具体类多态,抽象类多态,接口多态;
注意:
无论是向上还是向下,两种类型之间必须要有继承关系,没有继承关系,程序编译无法通过
向上转型,只要编译通过运行一定没有问题。
向下转型的隐患:类型转化异常,使用instanceof运算符可以避免以上异常
语法格式: (引用 instanceof 数据类型名) 以上运算执行的结果是 布尔类型,结果可能是true/false
(a instanceof Animal)
true: a这个引用指向的对象是一个Animal类型;
false: a这个引用指向的对象不是一个Animal类型;
编程好习惯:
在进行强制类型转换的时候,建议采用instanceof运算符进行判断,避免ClassCastException的发生
例题:
Animal、Cat、Bird之间的关系:
Cat、Bird 继承 Animal
Cat、Bird之间没有继承关系
/*
* 动物类
*/
public class 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 Bird extends Animal {
public void move(){
System.out.println("鸟在叫~!");
}
}
public class Test {
public static void main(String[] args) {
//以前编写的程序
Animal a1 = new Animal();
a1.move();
Cat c1 = new Cat();
c1.move();
c1.catchMouse();
//使用多态语法机制
/*
* 1.Animal 和 Cat 之间存在继承关系 Animal是父类
* 2.Cat is a Animal
* 3.new Cat()创建的对象类型是cat,a2这个引用的数据是Animal,可见它用了类型转化
* 4.子类转化成父类型(向上转型)自动类型转化
*5.Java中允许: 父类型引用子类型语向
*/
/*
* java程序分为编译阶段和运行阶段
* 先分析编译阶段,再分析运行阶段 编译无法通过 根本无法运行
* 编译阶段检测a2这个引用数据类型为Animal,由于Animal.class字节码当中有move()所有编译通过
* 无论cat有没有重写move方法,运行阶段一定要用的是cat对象的move方法,因为底层真实对象是就是cat对象
* 父类型引用指向子类型对象这种机制导致程序在编译阶段绑定和运行阶段绑定两种不同的形态/状态,这种机制可以成为一种多态的语法机制。
*/
Animal a2 = new Cat(); //Animal父类;Cat子类
a2.move();
//a2.catchMouse(); //Animal中没有catchMouse方法,所以要实行向下转型
//强制类型转换
Cat c = (Cat)a2;
c.catchMouse();
//编译通过但是无法运行,因为Bird和Cat类型之间不存在任何继承关系
//Bird b3 = (Bird)a3;
//b3.move();
Animal a3 = new Cat();
if (a3 instanceof Cat) { //instanceof 翻译:实例
Cat c3 = (Cat)a3;
c3.catchMouse();
}
else if (a3 instanceof Bird) {
Bird b3 = (Bird)a3;
b3.move();
}
}
}
public class Test1 {
public static void main(String[] args) {
Animal a1 = new Animal();
a1.move();
//父类型引用指向子类型对象
Animal a2 = new Cat();
Animal a3 = new Bird();
a2.move();
//向下转型【只有当访问子类对象特有的特征时】
if (a2 instanceof Cat) {
Cat c2 = (Cat)a2;
c2.catchMouse();
}
else if (a3 instanceof Bird) {
Bird b3 = (Bird)a3;
b3.move();
}
}
}