封装
封装介绍
封装(encapsulation)就是把抽象出的数据[属性]和对数据的操作[方法]封装在一起,数据被保护在内部,程序的其他部分只有通过被授权的操作[方法],才能对数据进行操作。
封装的理解和好处
1)隐藏实现细节:方法(连接数据库)<一调用(传入参数..)
2)可以对数据进行验证,保证安全合理
封装的实现步骤(三步走)
1)将属性进行私有化private 【不能直接修改属性】
2)提供一个公共的(public)set方法,用于对属性判断并赋值
public void setXxx(类型 参数名){//Xxx 表示某个属性
//加入数据验证的业务逻辑
属性 = 参数名;
}
3)提供一个公共的(public)get方法,用于获取属性的值
public 数据类型 getXxx(){//权限判断,Xxx 表示某个属性
return xx;
}
实例
/**
* 创建程序,在其中定义两个类:Account和AccountTest类体会Java的封装性。
* Account类要求具有属性:姓名(长度为2位3位或4位)、余额(必须>20)、
* 密码(必须是六位), 如果不满足,则给出提示信息,并给默认值(程序员自己定)
* 通过setXxx的方法给Account 的属性赋值。
* 在AccountTest中测试
*/
public class Account {
//为了封装,将3个属性设置为private
private String name;
private double balance;
private String pwd;
//提供两个构造器
public Account() {
}
public Account(String name, double balance, String pwd) {
this.setName(name);
this.setBalance(balance);
this.setPwd(pwd);
}
public String getName() {
return name;
}
//姓名(长度为2位3位或4位)
public void setName(String name) {
if (name.length() >= 2 && name.length() <= 4) {
this.name = name;
} else {
System.out.println("姓名要求(长度为2位3位或4位),默认值 无名");
this.name = "无名";
}
}
public double getBalance() {
return balance;
}
//余额(必须>20)
public void setBalance(double balance) {
if (balance > 20) {
this.balance = balance;
} else {
System.out.println("余额(必须>20) 默认为0");
}
}
public String getPwd() {
return pwd;
}
//密码(必须是六位)
public void setPwd(String pwd) {
if (pwd.length() == 6) {
this.pwd = pwd;
} else {
System.out.println("密码(必须是六位)默认密码为 000000");
this.pwd = "000000";
}
}
//显示账号信息
public void showInfo() {
//可以增加权限的校验
System.out.println("账号信息 name=" + name + " 余额=" + balance + " 密码" + pwd);
// if() {
// System.out.println("账号信息 name=" + name + " 余额=" + balance + " 密码");
// }else{
// System.out.println("你无权查看...");
// }
}
}
继承
继承的基本介绍和示意图
Java中的继承是一个对象获取父对象的所有属性和行为的机制。继承可以解决代码复用,让我们的编程更加靠近人类思维.当多个类存在相同的属性(变量)和方法时,可以从这些类中抽象出父类,在父类中定义这些相同的属性和方法,所有的子类不需要重新定义这些属性和方法,只需要通过extends 来声明继承父类即可。
继承的基本语法
class 子类 extends 父类 {
}
1)子类就会自动拥有父类定义的属性和方法
2)父类又叫 超类,基类
3)子类又叫派生类
public class ExtendsTheory {
public static void main(String[] args) {
Son son = new Son();//内存的布局
//?-> 这时请大家注意,要按照查找关系来返回信息
//(1) 首先看子类是否有该属性
//(2) 如果子类有这个属性,并且可以访问,则返回信息
//(3) 如果子类没有这个属性,就看父类有没有这个属性(如果父类有该属性,并且可以访问,就返回信息..)
//(4) 如果父类没有就按照(3)的规则,继续找上级父类,直到Object...
System.out.println(son.name);//返回就是大头儿子
//System.out.println(son.age);//返回的就是39
//System.out.println(son.getAge());//返回的就是39
System.out.println(son.hobby);//返回的就是旅游
}
}
class GrandPa { //爷类
String name = "大头爷爷";
String hobby = "旅游";
}
class Father extends GrandPa {//父类
String name = "大头爸爸";
private int age = 39;
public int getAge() {
return age;
}
}
class Son extends Father { //子类
String name = "大头儿子";
}
继承给编程带来的便利
1)代码的复用性提高了
2)代码的扩展性和维护性提高了
继承的深入讨论/细节问题
1) 子类继承了所有的属性和方法,非私有的属性和方法可以在子类直接访问, 但是私有属性和方法不能在子类直接访 问,要通过父类提供公共的方法去访问
2) 子类必须调用父类的构造器, 完成父类的初始化
3) 当创建子类对象时,不管使用子类的哪个构造器,默认情况下总会去调用父类的无参构造器,如果父类没有提供无 参构造器,则必须在子类的构造器中用 super 去指定使用父类的哪个构造器完成对父类的初始化工作,否则,编译不会通过
4) 如果希望指定去调用父类的某个构造器,则显式的调用一下 : super(参数列表)
5) super 在使用时,必须放在构造器第一行(super 只能在构造器中使用)
6) super() 和 this() 都只能放在构造器第一行,因此这两个方法不能共存在一个构造器
7) java 所有类都是 Object 类的子类, Object 是所有类的基类.
8) 父类构造器的调用不限于直接父类!将一直往上追溯直到 Object 类(顶级父类)
9) 子类最多只能继承一个父类(指直接继承),即 java 中是单继承机制。 思考:如何让 A 类继承 B 类和 C 类? 【A 继承 B, B 继承 C】
10) 不能滥用继承,子类和父类之间必须满足 is-a 的逻辑关系
public class ExtendsDetail {
public static void main(String[] args) {
// System.out.println("===第 1 个对象====");
// Sub sub = new Sub(); //创建了子类对象 sub
// System.out.println("===第 2 个对象====");
// Sub sub2 = new Sub("jack"); //创建了子类对象 sub2
System.out.println("===第 3 对象====");
Sub sub3 = new Sub("king", 10); //创建了子类对象 sub2
//sub.sayOk();
}
}
多态
多[多种]态[状态]基本介绍
方法或对象具有多种形态。是面向对象的第三大特征,多态是建立在封装和继承基础之上的。
多态的具体体现
1) 方法的多态 PloyMethod.java
重写和重载就体现多态
public class PloyMethod {
public static void main(String[] args) {
//方法重载体现多态
A a = new A();
//这里我们传入不同的参数,就会调用不同sum方法,就体现多态
System.out.println(a.sum(10, 20));
System.out.println(a.sum(10, 20, 30));
//方法重写体现多态
B b = new B();
a.say();
b.say();
}
}
class B { //父类
public void say() {
System.out.println("B say() 方法被调用...");
}
}
class A extends B {//子类
public int sum(int n1, int n2){//和下面sum 构成重载
return n1 + n2;
}
public int sum(int n1, int n2, int n3){
return n1 + n2 + n3;
}
public void say() {
System.out.println("A say() 方法被调用...");
}
}
2) 对象的多态
1.一个对象的编译类型和运行类型可以不一致
2.编译类型在定义对象时,就确定了,不能改变
3.运行类型是可以变化的
4.编译类型看定义时 = 号 的左边,运行类型看 = 号的右边
Animal animal = new Dog();【animal 编译类型是Animal,运行类型Dog】
animal = new Cat(); 【animal的运行类型变成了Cat,编译类型仍然是Animal】
public class Animal {
public void cry() {
System.out.println("Animal cry() 动物在叫....");
}
}
public class Cat extends Animal {
public void cry() {
System.out.println("Cat cry() 小猫喵喵叫...");
}
}
public class Dog extends Animal {
public void cry() {
System.out.println("Dog cry() 小狗汪汪叫...");
}
}
public class PolyObject {
public static void main(String[] args) {
//体验对象多态特点
//animal 编译类型就是 Animal , 运行类型 Dog
Animal animal = new Dog();
//因为运行时 , 执行到改行时,animal 运行类型是 Dog,所以 cry 就是 Dog 的 cry
animal.cry(); //小狗汪汪叫
//animal 编译类型 Animal,运行类型就是 Cat
animal = new Cat();
animal.cry(); //小猫喵喵叫
}
}
多态注意事项和细节讨论
多态的前提是:两个对象(类)存在继承关系
多态的向上转型
1.本质:父类的引用指向了子类的对象
2.语法:父类类型 引用名 = new 子类类型();
3.特点:编译类型看左边,运行类型看右边。
可以调用父类中的所有成员(需遵守访问权限)
不能调用子类中特有成员;
最终运行效果看子类的具体实现!
多态的向下转型
1)语法:子类类型 引用名 = (子类类型) 父类引用;
2)只能强转父类的引用,不能强转父类的对象
3)要求父类的引用必须指向的是当前目标类型的对象
4)当向下转型后,可以调用子类类型中所有的成员
public class PolyDetail {
public static void main(String[] args) {
//向上转型: 父类的引用指向了子类的对象
//语法:父类类型引用名 = new 子类类型();
Animal animal = new Cat();
Object obj = new Cat();//可以吗? 可以 Object 也是 Cat的父类
//向上转型调用方法的规则如下:
//(1)可以调用父类中的所有成员(需遵守访问权限)
//(2)但是不能调用子类的特有的成员
//(#)因为在编译阶段,能调用哪些成员,是由编译类型来决定的
//animal.catchMouse();错误
//(4)最终运行效果看子类(运行类型)的具体实现, 即调用方法时,按照从子类(运行类型)开始查找方法
//,然后调用,规则我前面我们讲的方法调用规则一致。
animal.eat();//猫吃鱼..
animal.run();//跑
animal.show();//hello,你好
animal.sleep();//睡
//可以调用Cat的 catchMouse方法
//多态的向下转型
//(1)语法:子类类型 引用名 =(子类类型)父类引用;
//问一个问题? cat 的编译类型 Cat,运行类型是 Cat
Cat cat = (Cat) animal;
cat.catchMouse();//猫抓老鼠
//(2)要求父类的引用必须指向的是当前目标类型的对象
Dog dog = (Dog) animal; //可以吗?
System.out.println("ok~~");
}
}
java 的动态绑定机制
public class DynamicBinding {
public static void main(String[] args) {
//a 的编译类型 A, 运行类型 B
A a = new B();//向上转型
System.out.println(a.sum());//?40 -> 30
System.out.println(a.sum1());//?30-> 20
}
}
class A {//父类
public int i = 10;
//动态绑定机制:
public int sum() {//父类sum()
return getI() + 10;//20 + 10
}
public int sum1() {//父类sum1()
return i + 10;//10 + 10
}
public int getI() {//父类getI
return i;
}
}
class B extends A {//子类
public int i = 20;
// public int sum() {
// return i + 20;
// }
public int getI() {//子类getI()
return i;
}
// public int sum1() {
// return i + 10;
// }
}
多态的应用
多态参数
方法定义的形参类型为父类类型,实参类型允许为子类类型
public class PloyParameter {
public static void main(String[] args) {
Worker tom = new Worker("tom", 2500);
Manager milan = new Manager("milan", 5000, 200000);
PloyParameter ployParameter = new PloyParameter();
ployParameter.showEmpAnnual(tom);
ployParameter.showEmpAnnual(milan);
ployParameter.testWork(tom);
ployParameter.testWork(milan);
}
//showEmpAnnual(Employee e)
//实现获取任何员工对象的年工资,并在main方法中调用该方法 [e.getAnnual()]
public void showEmpAnnual(Employee e) {
System.out.println(e.getAnnual());//动态绑定机制.
}
//添加一个方法,testWork,如果是普通员工,则调用work方法,如果是经理,则调用manage方法
public void testWork(Employee e) {
if(e instanceof Worker) {
((Worker) e).work();//有向下转型操作
} else if(e instanceof Manager) {
((Manager) e).manage();//有向下转型操作
} else {
System.out.println("不做处理...");
}
}
}
多态数组
数组的定义类型为父类类型,里面保存的实际元素类型为子类类型
public class PloyArray {
public static void main(String[] args) {
//应用实例:现有一个继承结构如下:要求创建1个Person对象、
// 2个Student 对象和2个Teacher对象, 统一放在数组中,并调用每个对象say方法
Person[] persons = new Person[5];
persons[0] = new Person("jack", 20);
persons[1] = new Student("mary", 18, 100);
persons[2] = new Student("smith", 19, 30.1);
persons[3] = new Teacher("scott", 30, 20000);
persons[4] = new Teacher("king", 50, 25000);
//循环遍历多态数组,调用say
for (int i = 0; i < persons.length; i++) {
//老师提示: person[i] 编译类型是 Person ,运行类型是是根据实际情况有JVM来判断
System.out.println(persons[i].say());//动态绑定机制
//这里大家聪明. 使用 类型判断 + 向下转型.
if(persons[i] instanceof Student) {//判断person[i] 的运行类型是不是Student
Student student = (Student)persons[i];//向下转型
student.study();
//小伙伴也可以使用一条语句 ((Student)persons[i]).study();
} else if(persons[i] instanceof Teacher) {
Teacher teacher = (Teacher)persons[i];
teacher.teach();
} else if(persons[i] instanceof Person){
//System.out.println("你的类型有误, 请自己检查...");
} else {
System.out.println("你的类型有误, 请自己检查...");
}
}
}
}