目录
一.封装
1.基本介绍
封装(encapsulation)就是把抽象出的数据(属性)和对数据的操作(方法)封装在一起,数据被保护在内部,程序的其它部分只有通过被授权的操作,才能对数据进行操作
简而言之,就是对数据加以限制或进行保护,比如,需要调取对象private属性,可以通过设置验证码,对数据进行保护
2.封装的优点
1)隐藏实现细节
2)可以对数据进行验证,保证安全合理
3.封装实现的步骤(三步)
1)将属性进行私有化private(不能直接修改属性)
2)提供一个公共的(public)set方法,对属性进行判断和复制
public void setXxx (类型,参数名){Xxx 表示某个属性
加入数据验证或对数据进行赋值
属性 = 参数名}
3)提供一个公共的(public)get方法,用于获取属性的值
public 数据类型 getXxx(){权限判断,Xxx某个属性
return xx;}
4.入门案例
不能随便查看工人的年龄,工资的隐私,并对设置的年龄进行合理的验证,年龄必须在0——120,名字长度2——6,工资不能直接查看
package 面向对象中级;
import java.util.Scanner;
public class encap{
public static void main(String[] args) {
Person person = new Person();
person.setName("jack");
person.setAge(30);
person.setSalary(30000);
System.out.println("请输入验证码查看工资");
Scanner myscanner = new Scanner(System.in);
int n = myscanner.nextInt();
System.out.println(person.info(n));//验证码输入为123456时可以访问工资
}
}
class Person{
//封装
public String name;
private int age;
private double salary;
private String job;
//怎么在主类给age salar 初始化
public void setName(String name){
if (name.length() >= 2 && name.length() <= 6) {
this.name = name;
}else {
System.out.println("名字长度不对");
}
}
public String getName(){
return name;
}//快捷键ALT + insert
public int getAge() {
return age;
}
public void setAge(int age) {
//判断
if (age >= 1&& age <= 120) {
this.age = age;
}else {
System.out.println("年龄需在0——120,默认年龄10");
this.age = 10;//给一个默认年龄
}
}
public double getSalary(int n) {
if (n == 123456) {
return salary;
}else{
System.out.println("你的权限不够");
return 0.0;
}
}
public void setSalary(double salary) {
this.salary = salary;
}
public String getJob() {
return job;
}
public void setJob(String job) {
this.job = job;
}
//
public String info(int n){
return "信息为 name=" + name + " age="+age+" salary="+getSalary(n);
}
二.继承
1.基本介绍
当多个类存在相同的属性(变量)和方法时,可以从这些类中,抽象出父类,在父类中定义这些相同的属性和方法,所有的子类不需要重新定义这些属性和方法,只需要通过 extends 来声明继承父类即可
2.继承的基本语法
class 子类 extends 父类{
}
1)子类会自动拥有父类定义的属性和方法
2)父类又叫超类,基类
3)子类又叫派生类
3.继承的优点
1)代码的复用性提高
2)代码的扩展性和维护性提高
4.快速入门案例
创建一个学生类
package 面向对象中级.inherit.improve;
//父类,是Pupil和Graduate的父类
public class Student {
public String name;
public int age;
private double score;
public void setScore(double score) {
this.score = score;
}
public void showinfo(){
System.out.println("学生名字="+name+" 年龄="+age+" 成绩="+score);
}
}
添加pupil和graduate对象的特殊属性
package 面向对象中级.inherit.improve;
public class Pupil extends Student{//ctrl + h可以查看子类与父类的关系
public void testing(){
System.out.println("学生" + name + "正在考小学数学");
}
}
package 面向对象中级.inherit.improve;
public class Graduate extends Student{
public void testing(){
System.out.println("学生" + name + "正在考小学数学");
}
}
测试
package 面向对象中级.inherit.improve;
import 面向对象中级.inherit.Graduate;
import 面向对象中级.inherit.Pupil;
import 面向对象中级.inherit.detail.Sub;
public class Test {
public static void main(String[] args) {
面向对象中级.inherit.Pupil pupil = new Pupil();
pupil.name = "小明-";
pupil.age = 10;
pupil.testing();
pupil.setScore(60);
pupil.showinfo();
System.out.println("========");
面向对象中级.inherit.Graduate graduate = new Graduate();
graduate.name = "小黑";
graduate.age = 20;
graduate.testing();
graduate.setScore(60);
graduate.showinfo();
}
}
结果
5.继承的使用细节
1) 子类继承了所有的属性和方法,非私有的属性和方法可以在子类直接访问, 但是私有属性和方法不能在子类直接访问,要通过父类提供公共的方法去访问
eg.
//父类
//4 个属性
public int n1 = 100;
protected int n2 = 200;
int n3 = 300;
private int n4 = 400;
//父类提供一个 public 的方法,返回了 n4
public int getN4() {
return n4;
}
public void sayOk(){//非私有的属性和方法可以在子类直接访问
//但是私有属性和方法不能在子类直接访问
//可以间接在父类提供一个公共的方法访问n4
System.out.println(n1 + " "+n2+" "+n3+" "+getN4());
2) 子类必须调用父类的构造器, 完成父类的初始化
public Sub() {
System.out.println("sub()...");
}
//若没调用,则调用super();//默认调用父类的无参构造器
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 的逻辑关系
eg.Cat is a Animal 即 可写成public class Cat extends Animal
六.继承实质
1) 首先看子类是否有该属性
2) 如果子类有这个属性,并且可以访问,则返回信息
3) 如果子类没有这个属性,就看父类有没有这个属性(如果父类有该属性,并且可以访问,就返回信息..)
4) 如果父类没有就按照(3)的规则,继续找上级父类,直到 Object...
观察下列输出结果
System.out.println(son.name);//大头儿子
//System.out.println(son.age);//报错
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.具体体现
A a = new A();
//体现出形参列表具有多种形态
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() 方法被调用...");
}
}
3.对象的多态
1)一个对象的编译类型和运行类型可以不一致
2)编译类型在定义对象时,就确定了,不能改变
3)运行类型时可以变化的
4)编译类型看定义时 = 号的左边,运行类型看 = 号的右边
重点理解编译类型和运行类型(可以看我转载的Java将子类对象赋值给父类对象的文章,讲的非常细致)
要理解编译类型和运行类型,首先我认为我们要弄清什么是编译,什么是运行。编译是声明对象的类型,分配属性,检查语法错误等;运行是,将对象加载内存(一般用new,反射也常用), 运行代码执行功能等。我们举个例子,我们有个Animal类,还有个Dog类,且Dog extends Animal,Animal animal = new Dog();这里的animal的编译类型时Animal,而运行类型是Dog,这句代码真正的对象其实是new Dog,而animal只是对对象的引用,如果大家实在不理解为什么Animal是编译类型,Dog是运行类型,给大家举个例子,一头披着羊皮的狼,它的本质肯定是狼,这是毋庸置疑的,但是它却占这羊的身体(内存空间),当它做一下行为(方法)时,比如吃草调用的就是羊的身体(内存空间),所以当我们调用animal的属性的时候就看它的父类,当我们调用方法时就把它看成子类(比如羊吃草),不知道各位读者能理解编译类型和运行类型,反正我是这样理解的(O^ ~ ^O)
若实在理解不了,就记住当我们用到它的方法时,我便把它看成子类对象;若用到它的属性时,我把它看成父类对象
下面代码帮助大家理解,看看输出结果是什么?
package Polydetail;
public class Animal {
String name = "动物";
int age = 10;
public void sleep(){
System.out.println("睡");
}
public void run(){
System.out.println("跑");
}
public void eat(){
System.out.println("吃");
}
}
package Polydetail;
public class Dog extends Animal{
String name = "狗";
public void eat(){
System.out.println("吃鱼");
}
}
package Polydetail;
public class Test {
public static void main(String[] args) {
Animal animal = new Dog();
animal.run();
animal.eat();
System.out.println(animal.name);
}
}
4.多态的使用细节
1)多态的前提:
两个对象(类)存在继承关系
2)向上转型
(相当于在四中举得Animal和Dog的例子)
a.本质:父类的引用指向子类的对象
b.语法:父类类型 引用名 = new 子类类型();
b.特点:编译类型看左边,运行类型看右边
可以调用父类中所有成员(对象,方法...)(需要遵守访问权限)
不能调用子类中特有的成员
最终运行效果看子类的具体体现
3.向下转型
a.语法 :子类类型 引用名 = (子类类型) 父类引用
b.只能强转父类的引用,不能强转父类的对象
c.要求父类的引用必须指向当前目标类型的对象
d.当向下转型后,可以调用子类类型中所有成员
看看下面代码的输出结果
package Detail01;
public class Animal {
String name = "动物";
int age = 10;
public void sleep() {
System.out.println("睡");
}
public void run() {
System.out.println("跑");
}
public void eat() {
System.out.println("吃");
}
}
package Detail01;
public class Cat extends Animal{
public void eat(){//方法重写
System.out.println("猫吃鱼");
}
public void catchMouse(){//Cat 特有方法
System.out.println("猫抓老鼠");
}
}
package Detail01;
public class Dog extends Animal{
public void eat(){
System.out.println("狗吃骨头");
}
}
package Detail01;
public class Polydetail {
public static void main(String[] args) {
Animal animal = new Cat();
Object obj = new Cat();//Object 也是 Cat 的父类
//animal.catchMouse();错误
animal.eat();//猫吃鱼.. animal.run();//跑
animal.show();//hello,你好
animal.sleep();//睡
Cat cat = (Cat) animal;
cat.catchMouse();//猫抓老鼠
// Dog dog = (Dog) animal; //可以吗?
// dog.eat();//错误的,因为现在animal指向cat的内存,
//如果我们要执行上面的那条语句,
//就相当于与把cat转成dao,这显然是错误
System.out.println("ok~~");
}
}
5.instanceof比较操作符
用于判断断对象的类型是否为 XX 类型或 XX 类型的子类型(是运行类型还是编译类型呢?)
看看下面代码输出结果时T还是F
class AA{}
class BB extends AA{}
BB bb = new BB();
System.out.println(bb instanceof BB);// true
System.out.println(bb instanceof AA);// true
//aa 编译类型 AA, 运行类型是 BB
//BB 是 AA 子类
AA aa = new BB();
System.out.println(aa instanceof AA);
System.out.println(aa instanceof BB);//由此看出是看运行类型
Object obj = new Object();
System.out.println(obj instanceof AA);//false
String str = "hello";
//System.out.println(str instanceof AA);
System.out.println(str instanceof Object);//true
6.动态绑定机制
1.当调用对象方法的时候,该方法会和对象的内存地址/运行类型绑定
2.当调用对象属性时,没有动态绑定机制,哪里声明哪里使用
看看下面代码的输出结果
package Detail02;
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;
// }
}
7.多态数组的应用
1)多态数组
package Polyarr;
public class Person {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String say(){
return name + " " + age;
}
}
package Polyarr;
public class Student extends Person{
private double score;
public Student(String name, int age, double score) {
super(name, age);
this.score = score;
}
public double getScore() {
return score;
}
public void setScore(double score) {
this.score = score;
}
public String say(){
return super.say() + " " + score;
}
}
package Polyarr;
public class Teacher extends Person{
private double salary;
public Teacher(String name, int age, double salary) {
super(name, age);
this.salary = salary;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
public String say(){
return super.say() + " " + salary;
}
}
package Polyarr;
public class arr_ {
public static void main(String[] args) {
Person[] persons = new Person[5];
persons[0] = new Person("jack",20);
persons[1] = new Student("jack",18,100);
persons[2] = new Student("jack",19,10);
persons[3] = new Teacher("king",21,200);
persons[4] = new Teacher("sa",12,2000);
for (int i = 0; i < 5; i++) {
System.out.println(persons[i].say());
}
}
}
2)多态参数
package Polyparamaeter;
public class Employee {
private String name;
private double salary;
public Employee(String name, double salary) {
this.name = name;
this.salary = salary;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
public double getAnnual(){
return 12 * salary;
}
}
package Polyparamaeter;
public class Manager extends Employee{
private double bonus;
public Manager(String name, double salary, double bonus) {
super(name, salary);
this.bonus = bonus;
}
public double getBonus() {
return bonus;
}
public void setBonus(double bonus) {
this.bonus = bonus;
}
public void manage(){
System.out.println(getName() + "管理");
}
@Override
public double getAnnual() {
return super.getAnnual() + bonus;
}
}
package Polyparamaeter;
public class Worker extends Employee{
public Worker(String name, double salary) {
super(name, salary);
}
public void work(){
System.out.println(getName() + "工作");
}
@Override
public double getAnnual() {
return super.getAnnual();
}
}
package Polyparamaeter;
public class Test {
public static void main(String[] args) {
Worker tom = new Worker("tom", 2500);
Manager jack = new Manager("jack", 5000, 200000);
Test test = new Test();
test.showEmpAnnual(tom);
test.showEmpAnnual(jack);
test.testwork(tom);
}
public void showEmpAnnual(Employee e){
System.out.println(e.getAnnual());//动态绑定机制
}
public void testwork(Employee e){
if (e instanceof Worker){
((Worker) e).work();//向下转型
}else if (e instanceof Manager){
((Manager) e).manage();//向下转型
}else {
System.out.println("no");
}
}
}