封装
为什么要封装?
现实生活中封装概念的引入
台式机电脑:机箱[ 主板 显卡 内存 电源 硬盘…]
机箱是保护里面硬件的安全
以上示例的总结:
都是通过物理层面封装的操作,达到从控制访问的目的
Java中为什么要封装?
因为可以任意修改对象的成员变量值不安全
案例:
/**
* 账户类
*/
public class Account {
/**账户名 */
String name;
/**账户余额 */
double money;
public Account() {
}
}
/**
* 封装测试类
*/
public class AccountTest {
public static void main(String[] args) {
//创建了一个对象
Account cang = new Account();
//给对象赋值
cang.name = "机箱";//初始值
cang.money = 10000000.00;//初始值
//没有封装,可以任意修改值
cang.name = "随便";//没有封装,可以任意修改姓名,不安全
cang.money = -1000000.00;//没有封装,可以任意修改余额,不安全
}
}
封装的作用
封装是为了保护内部数据的安全:
1. 不希望在外部类中随意访问类中的成员变量
2. 达到权限要求的才能访问。
3. 只是获取数据的时候,例如 单例模式
怎么封装
如何控制程序中的访问 ?
通过给类中的成员(字段,方法,构造方法)添加访问权限修饰符来实现封装(访问控制)
什么是访问权限:简单的认为访问权限就是不同级别的人能够干不同级别的事,不同级别的人能看到的页面是不同的
例子:比如做一个系统,不同人登录进去的访问权限不一样;
访问权限修饰符:
public 最大权限,被其修饰的成员,在任意目录下,都可以访问到 (所有类)
protected 在同包类和子类中都可以访问
默认不写 只能在同包类中访问
private 只能在当前类中访问
封装的步骤
1. 私有化成员变量(用private修饰成员变量)
2. 为每一个成员变量提供合理的
getXxx()方法 获取成员变量的值,如果当前成员变量类型是boolean类型,将getXxx()改为 isXxx()
setXxx(...)方法 设置成员变量的值
3. 提供一个无参构造
4. 该类用public修饰
封装案例:
/**
* 账户类
*/
public class Account {// 4. 该类用public修饰
/**账户名 1. 私有化成员变量(用private修饰成员变量) */
private String name;
/**账户余额 1. 私有化成员变量(用private修饰成员变量) */
private double money;
/**是否是VIP账户 1. 私有化成员变量(用private修饰成员变量) */
private boolean vip;
/**
* 2. 为每一个成员变量提供合理的
* getXxx()方法 获取成员变量的值,如果当前成员变量类型是boolean类型,将getXxx()改为 isXxx()
*
* setXxx(...)方法 设置成员变量的值
* @return
*/
public String getName(){
return name;
}
/**
* 2. 为每一个成员变量提供合理的
* getXxx()方法 获取成员变量的值,如果当前成员变量类型是boolean类型,将getXxx()改为 isXxx()
*
* setXxx(...)方法 设置成员变量的值
*/
public void setName(String n){
name = n;//将n赋值给成员变量name
}
public double getMoney(){
return money;
}
public void setMoney(double m){
//可以在方法中限制权限
money = m;//将m赋值给成员变量money
}
public boolean isVip(){
return vip;
}
public void setVip(boolean v){
vip = v;//将v赋值给成员变量vip
}
/**
* 3. 提供一个无参构造
*/
public Account() {
}
public Account(String n,double m,boolean v) {
//给成员变量赋值
name = n;
money = m;
vip = v;
}
}
封装的注意事项
1. 不是只有private才叫封装,private只是最大限度的封装而已。
2. get和set方法都是只能获取或者赋值一个成员变量
不能set(String n,double m,boolean v)赋值3个成员变量
3. 单一职能原则:功能最小化,不要想着一个方法写完所有的功能,因为代码复用率
继承
继承引入
三个类都有重复的代码,可以把这共同的代码抽出去,抽出去放到另外一个类里面;下面的3个类和上面的类需要发生一点关系(继承),上面的类叫做 父类(超类,基类,根类),下面的类叫子类(派生类,拓展类);
好处 : 提高了代码的复用性
继承作用
代码复用,提高开发效率和程序的扩展性。
Java中类继承的基本语法
① Java类中的继承的语法格式:
class A{}
class B extends A{}
A 就是B的父类、基类、根类、超类
B是A的子类、派生类、拓展类
② 验证:子类中是否可以继承到父类中的东西(通过创建子类对象来操作从父类继承的东西)
案例代码:
父类:
public class Animal {
String name;
int age;
public void eat() {
System.out.println("吃");
}
}
子类:
public class Person extends Animal{
/**
* 人类独有方法
*/
public void coding() {
System.out.println("敲代码...");
}
}
public class Pig extends Animal{
/**
* 猪类独有方法
*/
public void gongBaiCai() {
System.out.println("拱白菜...");
}
}
public class Bird extends Animal{
/**
* 鸟类独有方法
*/
public void fly() {
System.out.println("飞...");
}
}
测试类:
/**
* 继承测试类
*/
public class AnimalTest {
public static void main(String[] args) {
//创建子类对象
Person person = new Person();
Pig pig = new Pig();
//通过子类对象调用父类继承过来的成员
person.name = "张三";
person.age = 1;
person.eat();
System.out.println(person.name);
System.out.println(person.age);
//调用子类特有方法
person.coding();
pig.name = "佩奇";
pig.age = 7;
pig.eat();
System.out.println(pig.name);
System.out.println(pig.age);
//调用子类特有方法
pig.gongBaiCai();
}
}
子类可以从父类继承哪些成员?
除了构造方法不能被继承其他都可以继承过来
但是,私有化成员不能直接通过子类对象直接访问,但是可以通过继承过来的公共方法间接访问 代码如下:
public class Animal {
String str;
private int a;
static int b;
public Animal() {
System.out.println("无参构造...");
}
public Animal(int a) {
System.out.println("有参构造...");
}
public void test() {
System.out.println("普通方法");
}
public static void testStatic() {
System.out.println("静态方法..");
}
private void testPrivate() {
System.out.println("私有化方法..");
}
public int getA() {
return a;
}
public void setA(int a) {
this.a = a;
}
}
public class Person extends Animal{
/**
* 人类独有方法
*/
public void coding() {
System.out.println("敲代码...");
}
}
测试代码:
/**
* 测试继承哪些成员
*/
public class AnimalTest {
public static void main(String[] args) {
//创建子类对象
Person person = new Person();
//通过子类对象调用父类继承过来的普通成员变量
person.str = "张三";
//通过子类对象调用父类继承过来的私有化成员变量
// person.a = 1;//不能通过子类对象直接调用父类私有化成员
//通过子类对象调用父类继承过来的静态成员变量
// person.b = 2;//不要这样用。 这里编译的时候,会将person对象直接编译为类名的方式
//通过子类对象调用父类继承过来的普通方法
person.test();
//通过子类对象调用父类继承过来的静态方法
// person.testStatic();//不要这样用。 这里编译的时候,会将person对象直接编译为类名的方式
//通过子类对象调用父类继承过来的私有化方法
// person.testPrivate();//不能直接调用私有化方法
//子类调用可以通过父类公共方法间接调用父类中私有化的成员
person.setA(69);
int a = person.getA();
System.out.println(a);//69
//调用Object继承过来的方法
int hashCode = person.hashCode();
System.out.println(hashCode);
}
}
Java中类的继承特点
① 单继承(一个类只能够有一个直接父类)
② 多重继承(多层级的继承), 一个类可以有子类,子类还可以子类...
示例:
class A{}
class B extends A{}
class C extends B{}
class D extends C{}
③ 每一个类都有一个直接父类,如果没有看到显示的继承代码,那么就隐式继承Object
多态(polymorphic)
什么是多态?
简单理解 : 看成一种事物多种形态
示例 :
今天晚上大家请我吃大餐 : 龙虾 喝粥 思想大餐....
我准备买一辆车: 独轮车 自行车 拖拉机 布加迪模型....
Java 程序中的体现:
多态概念:
将子类对象装到父类的变量中保存(向上造型/向上转型),当父类变量调用方法的时候,如果子类重写了该方法,会直接执行子类重写之后的方法。(父类变量可以装任意类型的子类对象)。
多态案例1:
父类:
public class Animal {
int age = 1;
public void eat() {
System.out.println("吃....");
}
}
子类:
public class Person extends Animal{
int age = 2;
@Override
public void eat() {
System.out.println("吃肉...");
}
public void coding() {
System.out.println("撸代码...");
}
}
public class Pig extends Animal{
int age = 3;
@Override
public void eat() {
System.out.println("吃白菜");
}
public void gongBaiCai() {
System.out.println("拱白菜");
}
}
测试代码:
public class AnimalTest {
public static void main(String[] args) {
Animal animal = new Person();//多态的方式(向上造型/向上转型)
Animal animal2 = new Pig();//多态的方式(向上造型/向上转型)
//调用方法
animal.eat();//吃肉... 执行子类重写后的方法
animal2.eat();//吃白菜 执行子类重写后的方法
System.out.println(animal.age);//1 成员变量没有多态
// animal.gongBaiCai();//多态不能调用子类独有方法
}
}
多态作用:
可以屏蔽子类差异性,提高代码的扩展性
多态使用:
1. 向上造型/向上转型:
语法:
父类类型 父类变量 = new 子类类型();
父类变量.方法();//子类若重写,则会执行子类重写后的方法
例如:
Animal animal = new Person();//多态的方式(向上造型/向上转型)
Animal animal2 = new Pig();//多态的方式(向上造型/向上转型)
//调用方法
animal.eat();//吃肉... 执行子类重写后的方法
animal2.eat();//吃白菜 执行子类重写后的方法
2. 向下造型/向下转型: =>就是为了调用子类特有方
例如:(接上面案例)
现在需要调用子类Person中特有的方法或者调用子类Pig中特有的方法,不能调用怎么办?
这个时候就需要强制转换(向下造型/向下转型):
强制转换(向下造型/向下转型)语法:
数据类型 变量 = (数据类型)值/变量;
在向下造型前,必须进行类型判断,需要判断当前父类变量中装的是哪一个子类类型的对象
类型判断方式1:
if(父类变量 instanceof 子类类型1){
//强制类型转换
子类类型1 子类变量 = (子类类型1)父类变量;
//现在就可以调用子类特有方法
子类变量.子类特有方法(...);
}else if(父类变量 instanceof 子类类型2){
//强制类型转换
子类类型2 子类变量 = (子类类型2)父类变量;
//现在就可以调用子类特有方法
子类变量.子类特有方法(...);
}...
类型判断方式2:
if(父类变量.getClass() == 子类类型1.class){
//强制类型转换
子类类型1 子类变量 = (子类类型1)父类变量;
//现在就可以调用子类特有方法
子类变量.子类特有方法(...);
}else if(父类变量.getClass() == 子类类型2.class){
//强制类型转换
子类类型2 子类变量 = (子类类型2)父类变量;
//现在就可以调用子类特有方法
子类变量.子类特有方法(...);
}...
如果不进行类型判断再强转,就有可能发生ClassCastException类造型异常
测试类代码如下:
public class AnimalTest {
public static void main(String[] args) {
Animal animal = new Person();//多态的方式(向上造型/向上转型)
Animal animal2 = new Pig();//多态的方式(向上造型/向上转型)
animal = new Pig();//多态的方式(向上造型/向上转型)
//调用方法
animal.eat();
animal2.eat();
System.out.println(animal.age);//1 成员变量没有多态
//如果这里需要调用Pig类中特有方法,就需要将animal强转为Pig类型
//类型判断的方式1
if (animal instanceof Pig) {//判断animal中是不是装的Pig对象,如果是才强转
Pig pig = (Pig)animal;
//调用Pig特有方法
pig.gongBaiCai();
} else if (animal instanceof Person) {
//如果这里需要调用Person类中特有方法,就需要将animal强转为Person类型
Person person = (Person)animal;
//调用Person特有方法
person.coding();
}
//类型判断的方式2
if (animal.getClass() == Pig.class) {//判断animal中是不是装的Pig对象,如果是才强转
Pig pig = (Pig)animal;
//调用Pig特有方法
pig.gongBaiCai();
} else if (animal.getClass() == Person.class) {
//如果这里需要调用Person类中特有方法,就需要将animal强转为Person类型
Person person = (Person)animal;
//调用Person特有方法
person.coding();
}
}
}
1.4 多态注意事项:
多态案例2:
父类:
public class Vip {
/**
* 会员特权
*/
public void privilege() {
System.out.println("我有特权...");
}
}
子类:
public class Vip1 extends Vip{
/**
* 会员特权
*/
public void privilege() {
System.out.println("我是5000元俱乐部会员");
}
public void low() {
System.out.println("我很low");
}
}
public class Vip2 extends Vip{
/**
* 会员特权
*/
public void privilege() {
System.out.println("我是500000元俱乐部会员");
}
public void normal() {
System.out.println("我很一般");
}
}
public class Vip3 extends Vip{
/**
* 会员特权
*/
public void privilege() {
System.out.println("我是500000000000元俱乐部会员");
}
public void great() {
System.out.println("我很NB....");
}
}
测试类:
public class VipTest {
public static void main(String[] args) {
/*
* 模拟会员登陆的时候特权展示
*
*/
Vip vip = new Vip2();//屏蔽子类差异性
//调用特权
vip.privilege();//调用特权方法,如果子类重写了,会执行对应子类重写后的方法
//判断当前VIP中装的子类是哪一个,展示对应的特权
if (vip instanceof Vip1) {//类型判断
//强制转换
Vip1 vip1 = (Vip1)vip;
//调用特有方法
vip1.low();
}else if (vip instanceof Vip2) {//类型判断
//强制转换
Vip2 vip2 = (Vip2)vip;
//调用特有方法
vip2.normal();
}else if (vip instanceof Vip3) {//类型判断
//强制转换
Vip3 vip3 = (Vip3)vip;
//调用特有方法
vip3.great();
}
}
}
多态案例3:
父类:
public class Dog {
public void eat() {
System.out.println("吃...");
}
}
public class Hasky extends Dog {
@Override
public void eat() {
System.out.println("狗粮..");
}
}
public class Teddy extends Dog {
@Override
public void eat() {
System.out.println("吃天吃地吃空气");
}
}
public class Tudog extends Dog {
@Override
public void eat() {
System.out.println("啃骨头。。。");
}
}
public class Person {
/*public void feedDog(Hasky dog) {
dog.eat();
}
public void feedDog(Teddy dog) {
dog.eat();
}
public void feedDog(Tudog dog) {
dog.eat();
}
如果有几万种狗,就需要写几万个方法喂狗,不可取
*/
public void feedDog(Dog dog) {//屏蔽子类差异性。写一个父类类型,所有的子类对象都可以接收
dog.eat();
}
}
测试类:
public class DogTest {
public static void main(String[] args) {
//测试喂狗案例
Hasky hasky = new Hasky();
Tudog tudog = new Tudog();
Teddy teddy = new Teddy();
Person person = new Person();
person.feedDog(hasky);
person.feedDog(tudog);
person.feedDog(teddy);
}
}
1. 成员变量没有多态
2. 不能调用子类特有的方法,如果需要调用子类特有的方法,必须进行强制类型转换(向下造型/向 下转型),向下造型需要进行子类类型判断
3. 父类变量能点(调用)出哪些成员(成员变量和方法),是由当前类和其父类决定,优先从当前类 开始查找,直到找到Object了为止,如果Object中有没有,就不能调用
4. 多态调用方法的优先级顺序为:
该优先级为:this.show(O)、super.show(O)、this.show((super)O)、super.show((super)O)。
多态扩展练习:
代码如下:
public class A {
public String show(D obj) {
return ("A and D");
}
public String show(A obj) {
return ("A and A");
}
}
public class B extends A {
public String show(B obj) {
return ("B and B");
}
public String show(A obj) {
return ("B and A");
}
}
public class C extends B {
}
public class D extends B {
}
测试类:
public class Test {
public static void main(String[] args) {
A a1 = new A();
A a2 = new B();
B b = new B();
C c = new C();
D d = new D();
a1.show(b);// "A and A"
a1.show(c);// "A and A"
a1.show(d);// "A and D"
a2.show(b);// B and A
a2.show(c);// B and A
a2.show(d);// "A and D
b.show(b);// "B and B"
b.show(c);// "B and B"
b.show(d);// "A and D"
}
}