封装
封装的作用
封装操作和我们利用遥控器调节音量控制电视机很类似
封装的步骤
person.salary=2000;//报错了因为salary是private的所以只能在本类使用 这里就体现出来封装的重要性,对于私有属性的数据不能随意更改和访问
package Java_base_study;
public class Encap_example {
public static void main(String[] args) {
Person person = new Person();
person.name="zlh";
person.setSalary(2000);
}
}
class Person {
public String name;
private int age;
private int salary;
private String job;
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 int getSalary() {
return salary;
}
public void setSalary(int salary) {
this.salary = salary;
}
public String getJob() {
return job;
}
public void setJob(String job) {
this.job = job;
}
}
继承
继承的作用
继承的格式:
继承细节(子类必须先去调用父类的构造器因为会隐藏代替默认调用所以特容易忘):
这里需要注意非私有属性和方法可以在子类直接访问(为什么默认属性的数据也可以直接访问呢?)
注意点1:默认访问修饰符的特殊性
在同一个包下默认访问修饰符可以访问父类 但是假如跨包了就不能访问 打个比方: Package1: Class Student (属性有默认的int age,私有的private int score) Class grduate(extends Student)------>这时候由于他俩在一个包下所以子类可以访问父类的默认属性信息int age Package2: Class pupil(继承可以跨包吗?不管能不能反正现在pupil子类一定没办法访问到父类的默认属性信息int age)
注意点2(子类构造器在调用时必须先去调用父类的构造器!!!):
子类构造器在调用时必须先去调用父类的构造器 顺序: 父类构造器被调用() 子类构造器被调用() 这张图很重要记住
注意点3:
假如父类没有提供无参构造器,必须在子类构造器中用super关键字指定调用父类的哪个构造器 比如:父类只有一个有参构造器 public Student (String name,int age){ this.name=name; this.age=age; } 此时由于父类没有提供无参构造器,我们需要在子类构造器中加入super(“小张”,100); 表明我们调用的是public Student (String name,int age)这个构造器
注意点4:
super()只能在构造器中使用,且必须放在第一行
注意点5:
在构造器中可以使用this()调用另一个构造器但是必须放在第一行,所以this()和super()语句不能共存
注意点6:
java所有类都是Object类的子类, Object是所有类的基类.
注意点7:
子类最多只能直接继承一个父类(单继承机制)
继承的本质分析(重要)
继承的内存布局
属性访问(就近原则)
在就近原则查找属性是假如因为一个数据是私有的而无法访问会直接报错,不会再到父类查找数据 比如: son类的age我们定义为private那么访问son.age时,会直接报错,不会去找father.age然会返回father类的年龄!!!
继承例子
=Computer类=
package ExtendsExercise;
public class Computer {
private String cpu;
private int neicun;
private int disk;
public Computer(String cpu, int neicun, int disk) {
this.cpu = cpu;
this.neicun = neicun;
this.disk = disk;
}
public String getDetails(){
return("cpu"+cpu+"neicun"+neicun+"disk"+disk);
}
public String getCpu() {
return cpu;
}
public void setCpu(String cpu) {
this.cpu = cpu;
}
public int getNeicun() {
return neicun;
}
public void setNeicun(int neicun) {
this.neicun = neicun;
}
public int getDisk() {
return disk;
}
public void setDisk(int disk) {
this.disk = disk;
}
}
=ipad类=
package ExtendsExercise;
public class ipad extends Computer{
private String color;
public ipad(String cpu, int neicun, int disk, String color) {
super(cpu, neicun, disk);
this.color = color;
}
public String getInfo(){
return getDetails()+"color"+color;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
}
super方法
基本方法:
super.属性名和super.方法名访问父类的属性和方法 super()访问父类的构造器
使用super()方法的好处
-
调用父类的构造器的好处(分工明确,父类属性由父类初始化,子类的属性由子 类初始化) -
当子类中有和父类中的成员(属性和方法)重名时,为了访问父类的成员,必须通过super() 如果没有重名,使用super、this、直接访问是一样的效果!
分工明确
public ipad(String cpu, int neicun, int disk, String color) {
super(cpu, neicun, disk);
this.color = color;
}
三种方法
public void sum() {
System.out.println("B类的sum()");
super.cal();
例子:
多态
多态就是指方法和对象具有多种形态
小动物喂食问题引出多态
方法的多态就是方法的重载和重写
代码对比实现
package Java_base_study.homework.poly;
public class Test {
public static void main(String[] args) {
Master zhang = new Master("zhang");
Animal animal = new Cat("cjb");
Food food = new fish("鳕鱼");
zhang.feed(zhang,animal,food);
}
}
class Master{
public Master(String name) {
this.name = name;
}
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void feed(Master master,Animal animal,Food food){
System.out.println("主人"+master.name+"给动物"+animal.getName()+"喂"+food.getName());
}
}
class Animal{
private String name;
public Animal(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
class Cat extends Animal{
public Cat(String name) {
super(name);
}
}
class Food {
private String name;
public Food(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
class fish extends Food{
public fish(String name) {
super(name);
}
}
对象的多态(核心)
(1)一个对象的编译类型和运行类型可以不一致 (2)编译类型在定义对象时,就确定了,不能改变 (3)运行类型是可以变化的. (4)编译类型看定义时=号的左边,运行类型看=号的右边 Animal animal = new Dog(); 【animal编译类型是Animal,运行类型Dog】 animal = new Cat(); 【animal的运行类型变成了Cat,编译类型仍然是 Animal】
向上转型(解决给小动物喂食问题)
Animal animal = new Cat(); 向上转型:父类的引用指向了子类的对象 语法:父类类型引用名= new子类类型(); 0bject obj = new Cat();//可以 Object 也是 Cat的父类
向上转型调用方法规则
向上转型可以调用父类中的所有成员(需遵守访问权限) 但是不能调用子类的特有的成员 因为在编译阶段,能调用哪些成员,是由编译类型(Animal)来决定的------>animal.catchMouse();错误,catchMouse是猫类特有的方法 最终运行效果看子类的具体实现,即调用方法时,采用就近原则(子类有就要子类) 但注意了假如调用的是属性,属性没有重写的说法,它将调用根据编译类型调用属性,具体的看下面的属性重写问题一栏 总而言之记住一句话:属性看编译类型,方法看运行类型 animal.eat();//猫吃鱼,. animal.run(); animal.show() ;//eat()、run()都是animal父类中的方法
向下转型(解决无法调用子类成员问题)
写在前面:此处向下转型的代码是建立在前面向上转型代码的基础上的 1)语法:子类类型 引用名=(子类类型)父类引用; 2)只能强转父类的引用,不能强转父类的对象 3)要求父类的引用必须原先指向的就是当前目标类型的对象 4)当向下转型后,可以调用子类类型中所有的成员 一、首先语法:Cat cat=(Cat) animal;-------->将animal(父类的引用)强转为Cat(子类类型)
二、接下来不能强转父类的对象怎么理解? 父类的对象可以理解为一个具体的人(这个对象是永远不变的)----->不可能把一个特定人变成一只特定狗 但是他的引用是可以变的,比如他的身份是不断变的,从小学生—>大学生这是没关系的
三、要求父类的引用必须原先指向的就是当前目标类型的对象 在向上转型过程中,我们进行了如下操作:Animal animal = new Cat(); 就是说animal这个引用原先指向的就是Cat这个对象 错误示范:Dog dog=(Dog)animal(这句话就是将一只猫强转为一直狗,这是不允许的)
例子:
属性的重写问题(属性没有重写之说)
很搞!!!这句话很重要属性没有重写之说!属性的值看编译类型Base base = new Sub(); 属性和方法是不一样的假如这里是base.count()调用一个方法而不是调用base.count 属性那么,base.count()采用就近原则执行Sub类中方法 总而言之记住一句话:属性看编译类型,方法看运行类型
public class PolyDetail02 {
public static void main(String[] args){
Base base=new Sub();
System.out.println(base.count);
Sub sub = new Sub();
System.out.println(sub.count);
}
}
class Base {
int count = 10;
}
class Sub extends Base{
int count =20;
}
instanceof 方法
instanceOf比较操作符,用于判断对象的运行类型是否为XX类型或XX类型的子类型
public static void main(String[l args) {
BB bb = new BB();
System.out.println(bb instanceof BB);
System.out.println(bb instanceof AA);
AA aa = new BB();
system.out.println(aa instanceof AA);
System.out.println(aa instanceof BB);
}
假如说是判断对象的引用类型那么 aa instanceof AA 返回的是false;
动态绑定机制(非常重要)
动态绑定机制
1.当调用对象方法的时候,该方法会和该对象的内存地址/运行类型绑定 2.当调用对象属性时,==没有动态绑定机制,==哪里声明,那里使用
代码演示
class A{
public int i= 10;
public int sum() {return get1()+ 10;}
public int sum1(){return i+ 10;}
public int getl(){return i;}
}
class B extends A {
public int i = 20;
public int getl() {return i;}
}
{A a = new B();
System.out.printIn(a.sum());
System.out.println(a.sum1());
}
动态数组(多态运用)
如何调用子类特有的方法?
|