封装,继承,多态
封装
-
-
封装(数据的隐藏):通常,应禁止直接访问一个对象中数据的实际表示,而应通过操作接口来访问,称为信息隐藏。
-
属性私有:get/set。
-
代码如下:new这个Student类之后就会返回一个学生的对象s1。(对一个对象,一个类的封装)
package oop.demo01.demo04;
//1.提高程序的安全性,保护数据
//2.隐藏代码的实现细节
//3.统一接口,所有的方法都是get/set,形成了一个规范,用户调用的接口就是这个
//4.系统可维护性增加了
public class Application {
public static void main(String[] args) {
Student s1 = new Student();
s1.id = 3; //属性学号id可以直接调用赋值,通常都设为private私有化。
//s1.name = "zhangsan"; //属性名字不可以直接赋值,会报错,因为在Student类中private String name;属性是私有的。
s1.setName("zhangsan"); //setName方法需要单写,因为方法没有返回值
System.out.println(s1.getName()); //getName有返回值
//方法名,参数名都相同,方法一定相同。
System.out.println(s1.setName("lisi"));
s1.setAge(100);
System.out.println(s1.getAge()); //打印输出的是必须要有返回值的方法
}
}
代码二:
package oop.demo01.demo04;
public class Student {
//属性私有
private String name; //名字
int id; // 学号 默认为public
private char sex; // 性别
private int age;
//提供一些可以操纵这些属性的方法:get、set方法
//get 获得这个数据
public String getName(){
return this.name;
}
//set 给这个数据设置值
public String setName(String name){ //给这些属性赋值
this.name = name;
return this.name; //改写成有返回值的方法
}
//alt + insert getter and setter
//自动生成get set 方法
public char getSex() {
return sex;
}
public void setSex(char sex) {
this.sex = sex;
}
public int getAge() {
return age;
}
public void setAge(int age) { //可以添加验证性的安全性的判断
if(age<120 && age>0){ //有setAge方法,可以在方法中对输入值进行判断。直接赋值无法进行条件判断
this.age = age; //输入100,输出100
}else{
age = 3; //输入999,输出0,因为并没有给Student类的age属性赋值。
}
}
//学习()
//睡觉()
}
继承
-
继承的本质是对某一批类的抽象,从而实现的世界的建模。 (类之间的关系还有依赖,组合,聚合)。
-
extends意思是“扩展”,子类是父类的扩展。子类继承父类。
-
java类中只有单继承,没有多继承。(一个儿子只能有一个爸爸,一个爸爸可以有多个儿子)。
-
代码如下:父类
package oop.demo01.demo05;
//父类:Person类 子类继承父类,会拥有父类的全部方法(public)
public class Person {
public int money = 10_0000_0000;
private int bank = 123; //私有的东西无法继承
// default默认的,protected受保护的; 四个修饰符 public,protected,default,private优先级从高到低
//一般属性才是私有的,要继承的对象都是public.
public void say(){
System.out.println("说了一句话");
}
public int getBank() {
return bank;
}
public void setBank(int bank) {
this.bank = bank;
}
}
子类:
package oop.demo01.demo05;
//学生也是人,用extends继承 人这个类。
//Student类:派生类,子类
public class Student extends Person{
//Ctrl+H 打开继承树,继承的结构
}
子类二:
package oop.demo01.demo05;
//每一个类可以创建出很多对象。两个独立的类可以进一步抽象,抽象出一个父类Person。形成树状图的感觉。(宏观的把握)(封装底层)
//Teacher类:派生类,子类
public class Teacher {
}
测试类:
package oop.demo01.demo05;
public class Application {
public static void main(String[] args) {
Student student = new Student(); //创建一个student对象
student.say();
System.out.println(student.money);
//有一个看不见的类Object,但是它存在,像无参构造方法一样
//在java中,所有类都默认直接或间接继承Object类。(这个类中有很多本地的方法native)
//所以不用写extends Object。
}
}
super类
-
注意点:super是调用父类的构造方法,必须在构造方法放入第一个。
-
super必须只能出现在子类的方法或构造方法中。
-
super和this不能同时调用构造方法。
-
this:本身调用者这个对象。super:代表父类对象的应用。
this:没有继承也可以使用。super:在继承条件下,才可以使用。
构造方法:this();本类的构造。(this可以调用本类的其他方法) super();父类的构造。
-
代码如下:
package oop.demo01.demo05;
public class Application {
public static void main(String[] args) {
Student student = new Student();
//student.test("张三");
//student.test1();
}
}
代码二:
package oop.demo01.demo05;
//父类:Person类 子类继承父类,会拥有父类的全部方法(public)
public class Person {
public Person() {//alt+insert-->constructor,select none生成无参构造方法
System.out.println("Person无参执行了");
}
public Person(String name) {
this.name = name;
}
protected String name = "zhangsan";
public void print(){
System.out.println("Person");
}
private void print1(){ //私有的方法无法被继承
System.out.println("zs");
}
}
代码三:
package oop.demo01.demo05;
//学生也是人,用extends继承 人这个类。
//Student类:派生类,子类
public class Student extends Person{
public Student() { //无参构造内部方法体是空的
//隐藏代码:先调用了父类的无参构造
super();//调用父类的构造器,必须要在子类构造器中代码的第一行运行。
//this("hello"); //调用自己类的构造器,构造方法this();
//在无参构造方法中,调用其它构造器,要么调用父类的,要么调用子类的,只能在代码的第一行,只能二选一。
//在父类中,重写了有参构造,必须要把无参构造加上,否则后面的子类全都会报错。
//super("zhangsan");调用父类的有参构造
System.out.println("Student无参执行了");
}
public Student(String name) { //有参构造
this.name = name;
}
private String name = "lisi";
public void print(){
System.out.println("Student");
}
public void test1(){
print(); //Student 输出当前这个类的
this.print(); //Student
super.print(); //Person 调用了父类的方法
//super.print1(); 私有的无法继承,会报错。
}
public void test(String name){
System.out.println(name); //张三 实参赋给形参的值
System.out.println(this.name); //lisi 当前类的属性
System.out.println(super.name); //zhangsan 调到父类的属性
}
}
方法的重写
代码一:静态方法案例前三个
package oop.demo01.demo05;
public class B {
public static void test(){
System.out.println("B-->test");
}
}
代码二:
package oop.demo01.demo05;
public class A extends B{ //继承
public static void test(){
System.out.println("A-->test");
}
}
代码三:
package oop.demo01.demo05;
public class Application {
public static void main(String[] args) {
//静态方法的调用只和左边定义的数据类型有关。
A a = new A();
a.test(); //A-->test
// 父类的引用b指向了子类
B b = new A(); //执行实例化的过程,就是要先进入A类的无参构造方法,A继承了B,在无参构造方法中第一行先运行了B类的无参构造,所以new A()可以实现B类型的对象。
b.test(); //B-->test
}
}
代码四:静态方法和非静态方法区别很大
总结:重写需要有继承关系,子类重写父类的方法(不能重写属性),方法名,参数列表必须相同;修饰符范围可以扩大(public>protected>default>private);抛出的的异常:范围可以被缩小,但不能被扩大;比如:ClassNotFoundException-->Exception(变大)不行;
重写:子类和父类的方法必须一致,方法体不同。因为父类的功能,子类不一定需要或不一定满足。
代码五:
package oop.demo01.demo05;
public class B {
public void test1(){
System.out.println("B-->test");
}
}
代码六:
package oop.demo01.demo05;
public class A extends B{ //继承
//Override 重写 alt+insert -->override method-->test1,A类中有方法的时候是不能重写的。
代码七:
package oop.demo01.demo05;
public class Application {
public static void main(String[] args) {
//方法的调用只和左边定义的数据类型有关。
//A a = new A();
//a.test(); //A-->test
// 父类的引用b指向了子类
//B b = new A(); //执行实例化的过程,就是要先进入A类的无参构造方法,A继承了B,在无参构造方法中第一行先运行了B类的无参构造,所以new A()可以实现B类型的对象。
//b.test(); //B-->test
A aa = new A();
aa.test1(); //A-->test
B bb = new A(); //子类重写了父类的方法,只与非静态方法有关。
bb.test1(); //A-->test
}
}
多态
-
动态编译:类型:可扩展性
-
多态:即同一方法可以根据发送对象的不同(类型,重写)而采取多种不同的行为方式。
-
一个对象的是实际类型new A()是确定的,但可以指向对象的引用的类型A a,B b有很多(父类,有关系的类)。A a = new A();B b = new A();
-
多态存在的条件:有继承关系,子类重写父类的方法,父类引用B b指向子类对象new A()。(father f1 = new son();)
-
代码如下:
-
注意事项:多态是方法的多态,属性没有多态;父类和子类要有联系,类型不同强转会报错,比如:ClassCastException,类型转换异常;同一方法名,哪一个类(型)的,执行哪个类(型)对应的方法;
-
一些方法不能被重写:static方法:属于类,不属于任何一个实例(对象),和类相关;final:常量池中;private:私有的,不能被继承。
package oop.demo01.demo06;
public class Application {
public static void main(String[] args) {
//一个对象的是实际类型是确定的,new Student();
//new Student(); 那这个Student的类型肯定是确定的Student类
//new Person();
//可以指向的引用类型就不确定了: 父类的引用类型指向子类的类型。(可以指向这个对象的引用类型是任意的,父类型即可)
//Student能调用的方法都是自己的或者继承父类的。
Student s1 = new Student(); //都是学生new Student(),但表现出了多种状态Student s1,Person s2。
//Person父类,虽然可以指向子类,但不能调用子类独有的方法。
Person s2 = new Student(); //父类的引用指向子类的类型 String s2不行,String与Student没有关系。
Object s3 = new Student();
//对象能执行哪些方法,主要看对象左边的类型,和右边关系不大。Person s2 = new Student();
s2.run(); //run 虽然我们new的是Student,但依旧走了父类的方法,因为子类继承了父类的全部方法
s1.run(); //一旦子类重写了父类的方法, s1.run();,s2.run();都执行子类的方法,结果为son。
//s2.eat(); //对象变量类型是Person类型的s2中,Person类中没有eat方法,所以调用不了。如果子类和父类都有eat方法,只要子类没有重写父类,就调用父类的方法,如果重写了,就调用子类的方法。
((Student)s2).eat(); //强制类型转换 Person->Student类型,高转低,s2的类型转换成Student类型,就可以调用Student类型中的方法了。
s1.eat(); //s1的 Student类型中有eat方法,所以可以调用。
}
}
父类:
package oop.demo01.demo06;
public class Person {
public void run(){
System.out.println("run");
}
}
子类:
package oop.demo01.demo06;
public class Student extends Person {