Java基础--封装、继承、多态


第一讲 封装

一、对象的封装

1、概念
        封装:是指隐藏对象的属性和实现细节,仅对外提供公共访问方式。
2、 好处
        a)将变化隔离。
        b)便于使用。
        c)提高重用性。
        d)调高安全性。
3、 原则
        a)  将不需要对外提供的内容都隐藏起来。
        b)  把属性都隐藏,提供公共方法对其访问。
4、 封装的表现形式之一——private(私有)
        private关键字:权限修饰符;用于修饰类中的成员(成员变量,成员函数);私有只在本类中有效。
 常用之一:
        将成员变量私有化,对外提供对应的setget方法对其进行访问。提高对数据访问的安全性。
        如:我有一个人对象,而年龄这一属性我不想被对象访问,我就可以将其设为private

2、定义一个类封装它的name,age属性

class Person
{
    private Person(){}
    private String name = "tsz";
    private int age;
    private static  String country = "cn";
    Person(String name,int age)
    {
        this.name = name;
        this.age = age;
    }
    public void setName(String name)
    {
        this.name = name;
    }
    public String getName()
    {
        return name;
    }
    public void speak()
    {
        System.out.println(this.name+"..."+this.age);
    }

    public static void  showCountry()
    {
        System.out.println("country="+Person.country);//静态的可以类名直接调用
        Person.method();
    }
    public static void method()
    {
        System.out.println("method run");
    }

}

class  PersonDemo
{
    public static void main(String[] args) 
    {
        Person p = new Person("zhangsan",20);
        p.setName("lisi");
        new Person();
    }
}

/*
Person p = new Person("zhangsan",20);

该句话都做了什么事情?
1,因为new用到了Person.class.所以会先找到Person.class文件并加载到内存中。
2,执行该类中的static代码块,如果有的话,给Person.class类进行初始化。
3,在堆内存中开辟空间,分配内存地址。
4,在堆内存中建立对象的特有属性。并进行默认初始化。
5,对属性进行显示初始化。
6,对对象进行构造代码块初始化。
7,对对象进行对应的构造函数初始化。
8,将内存地址付给栈内存中的p变量。

*/

3、注意

private :私有,权限修饰符:用于修饰类中的成员(成员变量,成员函数)。
私有只在本类中有效。

将name私有化以后,类以外即使建立了对象也不能直接访问。
但是人应该有年龄,就需要在Person类中提供对应访问age的方式。

*注意:私有仅仅是封装的一种表现形式。

之所以对外提供访问方式,就因为可以在访问方式中加入逻辑判断等语句。
对访问的数据进行操作。提高代码健壮性。

二、构造函数的详细解读
1、构造函数

1、 特点:
        a) 函数名与类名相同。
        b) 不用定义返回值类型。
        c) 不可以写return语句。
2、 作用:
        给对象进行初始化。
3、构造函数的小细节:
        当一个类中没有定义构造函数时,那么系统就会默认给该类加入一个空参数的构造函数。当在类中自定义了构造函数后,默认的构造函数就没有了。
4、构造函数和一般函数在写法上有不同。
在运行上也有不同:
        构造函数式在对象一建立就运行,给对象初始化。而一般方法是对象调用才执行,给是对象添加对象具备的功能。一个对象建立,构造函数只运行一次。而一般方法可以被该对象调用多次。
5、什么时候定义构造函数?
        当分析事物时,该事物存在具备一些特性或者行为,那么将这些内容定义在构造函数中。
6、构造代码块
       作用:给对象进行初始化。对象一建立就运行,而且优先于构造函数运行。
和构造函数的区别:
       构造代码块是给所有对象进行初始化。
       而构造函数是给对应的对象初始化。
构造代码块中定义的是不同对象共性的初始化内容。

2、构造函数实现

class Person
{
    private String name;
    private int age;

    /*
    构造代码块。
    作用:给对象进行初始化。
    对象一建立就运行,而且优先于构造函数执行。
    和构造函数的区别:
    构造代码块是给所有对象进行统一初始化,
    而构造函数是给对应的对象初始化。

    构造代码快中定义的是不同对象共性的初始化内容。

    */
    {
        //System.out.println("person code run");//构造代码块
        cry();
    }

    Person()/*构造函数*/
    {
        System.out.println("A: name="+name+",,age="+age);

    }
    /*构造函数*/
    Person(String n)
    {
        name = n;
        System.out.println("B: name="+name+",,age="+age);

        //cry();

    }
    /*
    public void setName(String n)
    {
        name  = n;
    }
    public String getName()
    {
        return name;
    }
    */
    Person(String n,int a)
    {
        name = n;
        age = a;
        System.out.println("C: name="+name+",,age="+age);
    }

    public void cry()
    {

        System.out.println("cry......");
    }
}

class  PersonDemo2
{
    public static void main(String[] args) 
    {
        Person p1 = new Person();
        Person p2 = new Person("lisi"); 
    }
}

第二讲 继承

一、继承(extends)
1、继承概述

(1)继承的体系结构:就是对要描述的事物进行不断的向上抽取,就出现了体系结构。
要了解这个体系结构中最共性的内容,就看最顶层的类。
要使用这个体系的功能,就用最底层的类创建对象。
(2)继承的好处:
A:继承的出现,提高了代码的复用性。
B:继承的出现,让类与类之间产生了关系,extends来表示,这个关系的出现,为后面我们讲面向对象的第三个特点
多态打下了基础。
(3)特点
A:java只支持单继承(其实确切的说是java对多继承进行了优化,避免了安全问题)。
B:java支持多重(层)继承。
(4)注意:
A:子类可以直接访问父类中的非私有的属性和行为。
B:不要仅为了获取其他类中部分功能而去继承。
C:类与类之间要有所属( " is a " )关系,xx1是xx2的一种。
如何判断A和B是否有继承关系?
A如果继承B,那么就可以说A是B的一种。

2、继承的实例
举例:将学生和工人的共性描述提取出来,单独进行描述,只要让学生和工人与单独描述的这个类有关系,就可以了。

class Person
{
    String name;
    int age;

}
class Student extends Person
{
        void study()
    {
        System.out.println("good study");
    }
}

class Worker extends Person
{
    void work()
    {
        System.out.println("good work");
    }
}



class ExtendsDemo 
{
    public static void main(String[] args) 
    {
        Student s = new Student();
        s.name = "zhagnsan";
    }
}

3、继承后子父类之间成员的关系
(1)成员变量

class Fu{
    int num = 5;
}

class Zi extends Fu{
    int num = 20;


    public void show() {
        int num = 30;
        System.out.println("num:"+num);
        //当局部变量和成员变量重名的时候用this来区分
        System.out.println("this num:"+this.num);
        //当子类和父类出现了同名变量,用super来区分
        System.out.println("father num:"+super.num);
    }
}
总结:在一个类中如果方法中的局部变量和方法外的成员变量重名,那么如果在方法内输出这变量,就是方法自己的变量里的值,
想要区分要用this,加上this.就是输出成员变量的值
在子父类中如果出现成员变量重名的时候,在子类输出会输出自己的变量里的值,想要区分要用super,加上super.就是输出
父类里变量的值

    thissuper的区分:
      **this代表本类对象的引用
    super本类对象父类的引用。
      **this可以用于区分局部变量和成员变量同名的情况。
    super可以用于区分子类和父类成员变量同名的情况。
      **一般,子类中不会出现和父类同名的成员变量。面试可能问到。

(2)成员方法

class Fu {
    public void show() {
        System.out.println("fu show");
    }
    public void method() {}
}

class Zi extends Fu{

    public void show(){

        System.out.println("zi show");
    }
}
子类中存在和父类成员方法同名的这种现象,叫做重写,复写,覆盖。
重写(override)和重载(overload)的区别:
重载的特点:
    **在同一类中。
    **方法名相同,参数列表不同。
重写的特点:
    **要有继承关系。在子父类中
    **方法的声明相同。(方法名和参数列表都相同)
        ***覆盖时,子类方法权限一定要大于等于父类方法权限
        父类的权限不能是私有的
        ***静态只能覆盖静态。

(3)构造方法

class Fu{

    Fu(){}

    Fu(int age){        
        System.out.println("father age:"+age);
    }
}

class Zi extends Fu{
    Zi(){
        this(40);
        System.out.println("son");
    }

    Zi(int age){    
        super();
        System.out.println("son age:"+age);
    }
}

Zi z = new Zi();  

Zi z = new Zi(30);

总结:子类中所有的构造方法默认都会访问父类中空参数的构造方法。
    **因为每一个构造方法的第一行都有一条默认的语句super();

      当父类中没有空参数的构造方法时,子类的构造函数必须通过this
      或者super语句指定要访问的构造方法。或者手动提供无参构造方法。

      this(...):调用本类中的构造方法
      super(...):调用父类中的构造方法

构造方法用于创建对象,并进行初始化.建议如果你写了有参的构造函数,也要把空参的构造函数再手动加上
否则你定义了有参的构造函数,空参的系统就不会再给了
你这样创建对象的时候就会报错Person p = new Person();//这句话是会去找空参的构造函数

 class Person{
        Person(){}

    Person(int age){
        this.age = age;
    }

    Person(int age,String name){
        this(age);
        //this.age = age;
        this.name = name;
    }
 }

      //Person p =new Person();  //系统默认给出无参构造

      //当你手动给出构造方法后,系统就不会再给出默认的空的构造方法。


      手动无参数,如果你想给属性赋值或者做一些初始化,无参你别删不就行了吗。
    class Demo{
        private String name;
        Demo(){}

        public void setName(String name){
            this.name = name;
        }

        public String getName(){
            return name;
        }
    }

4、final可以用来修饰什么呢?

(1)final可以用来修饰类:被fainl修饰的类不能被继承。
(2)final可以用来修饰成员方法:被final修饰的成员方法不能被重写。
(3)final可以用来修饰变量:被final修饰的变量为常量,值不能被修改。
(4)被final修饰的变量是一个常量只能赋值一次,既可以修饰成员变量,有可以修饰局部变量。
    当在描述事物时,一些数据的出现值是固定的,那么这时为了增强阅读性,都给这些值起个名字。方便于阅读。
    而这个值不需要改变,所以加上final修饰。作为常量:常量的书写规范所有字母都大写,如果由多个单词组成。
    单词间通过_连接。
(5)内部类定义在类中的局部位置上是,只能访问该局部被final修饰的局部变量。
   常量的命名规范:要求大写。
   final double PI = 3.14;
   final修饰的变量可以在声明的时候直接赋值,还可以在构造方法可以给final修饰的变量赋值。

实例:
class Demo
{
    final int x = 3;
    public static final double PI = 3.14;
    final void show1()
    {}
    void show2()
    {
        final int y = 4;
        System.out.println(3.14);
    }
}
class SubDemo extends Demo
{
    //void show1(){}
}
class FinalDemo 
{
    public static void main(String[] args) 
    {
        System.out.println("Hello World!");
    }
}

第三讲 多态

1、多态的概述
多态:可以理解为事物存在的多种体现形态。

(1)某一类事物的多种存在形态。
方法重载(静态多态)
方法重写(动态多态,对象多态)
(2)对象多态的前提
A:类与类(或接口)要有继承(或实现)关系。
B:一定要有方法的重写(覆盖)。
C:一定要有父类或者接口的引用指向子类的对象。
(3)多态的好处
    多态的出现大大的提高程序的扩展性。
(4)多态的弊端:
    提高了扩展性,但是只能使用父类的引用访问父类中的成员。

2、多态的基本运用

abstract class Animal
{
    abstract void eat();

}

class Cat extends Animal
{
    public void eat()
    {
        System.out.println("吃鱼");
    }
    public void catchMouse()
    {
        System.out.println("抓老鼠");
    }
}


class Dog extends Animal
{
    public void eat()
    {
        System.out.println("吃骨头");
    }
    public void kanJia()
    {
        System.out.println("看家");
    }
}


class Pig extends Animal
{
    public void eat()
    {
        System.out.println("饲料");
    }
    public void gongDi()
    {
        System.out.println("拱地");
    }
}

class DuoTaiDemo 
{
    public static void main(String[] args) 
    {
        //Cat c = new Cat();//创建cat对象
        //c.eat();
        /*
        Cat c1 = new Cat();
        function(c1);//函数的参数是animal的子类对象

        function(new Dog());
        function(new Pig());
        */

        //Animal c = new Cat();
        //c.eat();


        function(new Cat());//直接传匿名对象



    }
    public static void function(Animal a)//Animal a = new Cat();
    {
        a.eat();
        //a.catchMouse();
    }
    /*
    public static void function(Cat c)//
    {
        c.eat();
    }
    public static void function(Dog d)
    {
        d.eat();
    }

    public static void function(Pig p)
    {
        p.eat();
    }
    */

}

3、继承重写是多态的一种表现

class Fu
{
    static int num = 5;
    void method1()
    {
        System.out.println("fu method_1");
    }
    void method2()
    {
        System.out.println("fu method_2");
    }
    static void method4()
    {
        System.out.println("fu method_4");
    }
}


class Zi extends Fu
{
    static int num = 8;
    void method1()
    {
        System.out.println("zi method_1");
    }
    void method3()
    {
        System.out.println("zi method_3");
    }

    static void method4()
    {
        System.out.println("zi method_4");
    }
}
class  DuoTaiDemo4
{
    public static void main(String[] args) 
    {
        //以左边为主
//      Fu f = new Zi();
//
//      System.out.println(f.num);//结果是父类的num=5
//
//      Zi z = new Zi();
//      System.out.println(z.num);

        //f.method1();
        //f.method2();
        //f.method3();

        Fu f = new Zi();
        System.out.println(f.num);//父类的num
        f.method4();//静态 的情况都要看左边,如果非静态看右边运行Zi

        Zi z = new Zi();
        z.method4();
    }
}

4、多态中成员的特点

Fu f = new Zi()
A、非静态方法
在编译时期:参阅引用型变量所属的类中是否有调用的方法。如果有,编译通过,如果没有编译失败。
在运行时期:参阅对象所属的类中是否有调用的方法。
简单总结就是:成员函数在多态调用时,编译看左边,运行看右边。
B、成员变量:编译和运行都看Fu
C:静态方法:编译和运行都看Fu。


举例: 动物的例子: 向上转型 Animal a = new Cat(); a.eat(); //a.catchMouse();

向下转型
Cat c = (Cat)a;
c.eat();
c.catchMouse();

//向上转型
Animal a = new Dog();
//向下转型 转换异常
//Cat c = (Cat)a;
Dog d = (Dog)a;

总结:无论是向上转型还是向下转型,变化的都是子类对象,绝对不能把父类对象强转为子类类型
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值