Java 封装
封装的介绍
封装,即隐藏对象的属性和实现细节,仅对外公开接口,控制在程序中属性的读和修改的访问级别;将抽象得到的数据和行为(或功能)相结合,形成一个有机的整体,也就是将数据与操作数据的源代码进行有机的结合,形成“类”,其中数据和函数都是类的成员。
封装的好处
1.可以隐藏实现的细节
2.可以对数据进行验证,保证其安全合理性
构造器和Set xx结合
java继承
1.关键字 extends
可以理解为代码的复用性,当多个类拥有相同的属性和方法时,我们可以从抽象出来一个父类,在这个父类定义相同的方法或属性,所有的子类不必重复去定义这些属性和方法,只需要用extends继承
注意
子类继承了父类的所有属性和方法,但是私有属性和方法不能在子类直接反问,要提供公共的方法来反问
子类必须调用父类的构造器来完成父类的初始化
//父类
public class Student {
public Student() {
System.out.println("父类构造器----");
}
}
//子类
public class Student2 extends Student{
public Student2(){
//为什么会调用父类的构造器
//super(); 这里默认去调用父类的无参构造器,写不写都有
System.out.println("子类0000");
}
}
//测试
public class Text {
public static void main(String[] args) {
Student2 s=new Student2();
}
}
结果 创建的是子类,先调用的是父类的构造器在调用子类构造器
//父类构造器----
//子类0000
但创建子类对象时,不管使用子类的有参还是无参构造器,默认都是先调用父类的无参构造器,参xv'cvb
这里我们把父类改成一个有参构造器
public class Student2 extends Student{
public Student2(String name){
System.out.println("子类0000");
}
}
public class Student2 extends Student{
public Student2(){
//父类没有提供无参构造器,这里就super去指定具体的父类构造器
super("miss");
System.out.println("子类0000");
}
}
注意super,this关键字在使用时,必须放到构造器的第一行(只能在构造器中使用),this和sper不能共存在一个构造器
java的所有类都是Object类的子类
父类构造器的调用不限于直接父类,就往上追索到object顶级父类
java是单继承,就是一个子类只能有一个直接父类,可以有多个间接父类,例如 A->B->C
java继承本质讲解
例子
public class Text2 {
public static void main(String[] args) {
Sun s=new Sun();
}
}
class GrandPa{
String name="大头爷爷";
String hobby="旅游";
}
class Frather extends GrandPa{
String name="大头爸爸";
int age=39;
}
class Sun extends Frather{
String name="小头儿子";
}
基本数据类型存在堆中
引用数据类型的值实际存在方法区中常量值中
大概加载步骤是,从大到小
如果去访问它的属性name和age,这可以说是就近原则,就是先从子类找一直到object类,通俗就是你没有,找你爸爸要->你爷爷->你老祖,如果没有就真没有
public class Text2 {
public static void main(String[] args) {
Sun s=new Sun();
System.out.println(s.name);
System.out.println(s.age);
}
}
//结果
小头儿子
39
方法的重写
类中重写父类方法建立在继承的基础之上的
1.子类的参数,方法名称要和父类一样
2.子类的返回类型要和父类的返回类型一样,或者是父类返回类型的子类
父类方法
public Object info(){
return true;
}
子类方法
子类和父类的返回类型一样
public Object info(){//可以
重写内容
}
或者是父类返回类型的子类
public String info(){
重写内容
}//可以
3.子类方法不能缩小父类的访问权限
例如父类的权限
String info(){}
子类
private String info(){}//错误
public String info(){}//正确
重载和重写比较
| 名称 | 发生范围 | 参数列表(形参) | 返回类型 | 方法名 | 修饰符 |
|---|---|---|---|---|---|
| 重载 | 一般在本类 | 类型,形参个数不同,顺序必须有一个不同 | 没有要求 | 必须一样 | 一样 |
| 重写 | 父子类 | 必须一样 | 一致,或是其子类 | 必须一样 | 一样或更大,不能比父类小 |
面向对象--多态
多态可以提高代码复用性和更利于维护
多态的使用时建立在封装和继承的基础上
多态核心
1.一个对象的编译类型可以和运行类型不一致(编译看左边,运行看右边)
//例如 这是一个父类的引用指向狗这个子类的对象
Animal animal=new Dog(); 这编译是Animal运行类型是Dog
2.编译类型在定义对象时就确定了,不可以改变
3.运行类型可以改变的
// 这是一个父类的引用指向猫这个子类的对象
Animal animal=new Cat();
package com.TaoGe.java;
public class Animal {
public void to(){
System.out.println("动物咆哮");
}
}
class Dog extends Animal{
public void to(){
System.out.println("狗子旺旺叫");
}
}
class cat extends Animal{
@Override
public void to() {
System.out.println("猫喵喵叫");
}
}
class Text{
public static void main(String[] args) {
Animal a=new Dog();
//执行到这运行类型是Dog
a.to();// 狗子旺旺叫
Animal a2=new cat();
//执行到这运行类型是cat
a2.to();//猫喵喵叫
}
}
多态向上转型
本质:就是父类的引用指向子类的对象
可以调用父类所有成员(注意访问权限)
不能调用子类特有成员(private修饰)
最终运行效果也是先从子类开始找,如果没有,则到父类
package com.TaoGe.java;
public class Person {
public void eat(){
System.out.println("人吃饭");
}
public void work(){
System.out.println("人散步");
}
}
class student extends Person{
@Override
public void eat() {
System.out.println("学生吃饭");
}
}
class Test3{
public static void main(String[] args) {
student s=new student();
s.eat();//学生吃饭
//这里子类没有work这个方法,父类有并且可以调用,则运行父类的
s.work();//人散步
}
}
多态向下转型
基本语法
子类类型 引用名=(子类类型)父类引用
只能强转父类引用,不能强转父类的对象
父类的引用必须指向当前目标类型的对象
多态的细节
1.属性没有重写之说,运行和编译看左边,和方法不同
package com.TaoGe.java;
class A{
int base=3;
}
class B extends A{
int base=5;
}
public class Text4 {
public static void main(String[] args) {
A a=new A();
System.out.println(a.base);//3
}
}
InstanceOf
结论:InstanceOf用来判断对象的运行时类型是某个类型,或为它的子类型
package com.TaoGe.java;
class A{}
class B extends A{}
public class Text4 {
public static void main(String[] args) {
B b=new B();
System.out.println(b instanceof B);//true
System.out.println(b instanceof A);//true
A a=new B();
System.out.println(a instanceof A);//true
System.out.println(a instanceof B );//true
}
}
java的动态绑定机制
1.但调用对象方法时,该方法就会和该对象的内存地址/运行类型判定
2.当调用对象属性时,没有动态判定机制,哪里调用哪里使用
简单实例
package com.TaoGe.java;
public class Text4 {
public static void main(String[] args) {
A a=new B();//向上转型
System.out.println(a.sum());//40 ?但子类没有sum方法时结果 30
System.out.println(a.sum1());//30 ? 但子类没有sum1方法时结果 20
}
}
class A{
public int i=10;
public int sum(){
return getI()+10;
}
public int sum1(){
return i+10;
}
public int getI(){
return i;
}
}
class B extends A{
public int i=20;
@Override
// public int sum() {
// return i+20;
// }
public int getI(){
return i;
}
// public int sum1() {
// return i+10;
// }
}
多态数组
数组的定义类型为父类类型,实际保存的是子类类型
package com.TaoGe;
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 + "\t" + age;
}
}
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;
}
@Override
public String say() {
return super.say()+"score="+score;
}
public void setScore(double score) {
this.score = score;
}
public void study(){
System.out.println("学生"+getName()+"正在学习");
}
}
class Teacher extends Person{
private double salary;
public Teacher(String name, int age,double salary) {
super(name, age);
this.salary=salary;
}
@Override
public String say() {
return super.say()+"salary="+salary;
}
public void teach(){
System.out.println("老师"+getName()+"正在上课");
}
}
class Test{
public static void main(String[] args) {
Person[] p=new Person[5];
p[0]=new Student("awea",23,45.5);
p[1]=new Student("aeae",323,12.3);
p[2]=new Student("ccc",24,232.4);
p[3]=new Person("ddd",44);
p[4]=new Teacher("aea",34,60000);
for (int i = 0; i <p.length ; i++) {
//编译类型是person,运行类型根据jvm来决定
System.out.println(p[i].say());//动态绑定
//这里调用子类特有的方法,根据类型判断和向下转型
if (p[i] instanceof Student){
((Student)p[i]).study();
}else if (p[i] instanceof Teacher){
((Teacher)p[i]).teach();
}else if (p[i] instanceof Person){
} else {
System.out.println("类型有误");
}
}
}
}
多态参数
方法定义的形参为父类类型,实参允许为子类类型
实战!
package com.TaoGe;
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 salary*12;
}
}
class Worker extends Employee{
public Worker(String name, double salary) {
super(name, salary);
}
public void towork(){
System.out.println("普通员工"+getName()+"打工人,人上人");
}
@Override
public double getAnnual() {
return super.getAnnual();
}
}
class manager extends Employee{
private double bonus;//奖金
public manager(String name, double salary,double bonus) {
super(name, salary);
this.bonus=bonus;
}
public void maage(){
System.out.println("经理"+getName()+"管理公司");
}
@Override
public double getAnnual() {
return super.getAnnual()+bonus;
}
}
class Text{
public static void main(String[] args) {
//创建当前类的实例
Text t=new Text();
//经理
Employee e=new manager("aaa",3000,2000);
System.out.println(t.showEmAnnus(e));
t.testWork(e);
//普通员工
Employee c=new Worker("bbb",2000);
System.out.println(t.showEmAnnus(c));
t.testWork(c);
}
public double showEmAnnus(Employee e){
return e.getAnnual();
}
public void testWork(Employee c){
if (c instanceof Worker){
((Worker)c).towork();
}else if (c instanceof manager){
((manager)c).maage();
}else if (c instanceof Employee){
}else {
System.out.println("啥也不是");
}
}
}