Java面向对象(二)

一、面向对象特征之一:封装和隐藏

  1、概述

    1.1、隐藏对象内部的复杂性,只对外公开简单的接口。便于外界调用,从而提高系统的可扩展性。通俗的说,把该隐藏的隐藏起来,该暴露的暴露出来。这就是封装的设计思想。

    1.2、高内聚:类的内部数据操作细节自己完成,不允许外部干涉。

       低耦合:仅对外部暴露少量的方法用于使用。

    1.3、当我们创建一个类的对象以后,我们可以通过“对象.属性”方式对对象的属性进行赋值。赋值操作要受到属性的数据类型和存储范围的制约。除此之外,没有其他制约条件。但是,在实际问题中,我们往往要给属性赋值加入额外的限制条件,这个条件就不能在属性声明时体现。我们只能通过方法进行限制条件的添加。(比如:setXxx(),同时我们要避免用户在使用“对象.属性”的方式对属性进行赋值,则需要将属性声明为私有的(private))。--------------------------------------------->>>>>>>>>>>>>>>>>>>>>>>此时针对属性就体现了封装性。

  2、封装性的体现

    1、我们将类的属性xxx私有化(private),同时提供公共(public )的方法来获取(getXxx())和设置(setXxx())该属性的值。

    2、不对外暴露的私有方法。

    3、单例模式等······

public class AnimalTest {
    public static void main(String[] args) {
        Animal a = new Animal();
        a.name = "大黄";
        a.age = 1;
//        a.legs = 4;//The field Animal.legs is not visible
//
//        a.show();//age = 1  name = 大黄  legs = 4
//        
//        a.legs = -1;
//        a.show();//age = 1  name = 大黄  legs = -1
        // 把对属性的操作封装起来
        a.setLegs(4);
        a.show();// age = 1 name = 大黄 legs = 4
        a.setLegs(-1);
//        System.out.println(a.legs);//The field Animal.legs is not visible
        System.out.println(a.getLegs());// 0
    }
}

class Animal {
    int age;
    String name;
//    int legs;// 腿的个数
    private int legs;

    //设置属性
    public void setLegs(int i) {
        if (i <= 0 || i % 2 != 0) {
            legs = 0;
        } else {
            legs = i;
        }
    }

    // 获取属性
    public int getLegs() {
        return legs;
    }

    public void eat() {
        System.out.println("动物进食。");
    }

    public void show() {
        System.out.println("age = " + age + "  name = " + name + "  legs = " + legs);
    }
}

  3、封装性的体现,需要权限修饰符来配合

    1、Java提供了4种权限。

修饰符   本类     同一个包 不同包的子类 同一个工程
private      
缺省    
protected  
public

    2、具体的:4种权限可以用来修饰类及类的内部结构:属性,方法,构造器,内部类。

           修饰类的话,只能使用缺省和public。

    3、总述:Java提供了4种权限修饰符,来修饰类的内部结构,体现类及类的内部i结构在被调用时的可见性大小。

package oop;

public class Order {
    private int oredrPrivate;
    int orderDefault;
    public int orderPublic;
    
    
    private void methodPrivate() {
        oredrPrivate = 1;
        orderDefault = 2;
        orderPublic = 3;
    }
    
    void methodDefault() {
        oredrPrivate = 1;
        orderDefault = 2;
        orderPublic = 3;
    }
    
    public void methodPublic() {
        oredrPrivate = 1;
        orderDefault = 2;
        orderPublic = 3;
    }
}
package oop;

public class OrderTest {
    public static void main(String[] args) {
        Order o = new Order();
//        出了Order类之后,私有结构就不可以在调用了
//        o.oredrPrivate = 1;//The field Order.oredrPrivate is not visible
        o.orderDefault = 2;
        o.orderPublic = 3;
        
        
        
        o.methodPublic();
        o.methodDefault();
//        出了Order类之后,私有结构就不可以在调用了
//        o.methodPrivate();//The method methodPrivate() from the type Order is not visible
    }
}
package oop1;

import oop.Order;

public class OrderTest {
    public static void main(String[] args) {
        Order o = new Order();
//        出了Order类所属的包之后,私有结构、缺省声明的结构就不可以在调用了
//        o.oredrPrivate = 1;//The field Order.oredrPrivate is not visible
//        o.orderDefault = 2;//The field Order.orderDefault is not visible
        o.orderPublic = 3;
        
        
        
        o.methodPublic();
//        出了Order类所属的包之后,私有结构、缺省声明的结构就不可以在调用了
//        o.methodDefault();//The field Order.orderDefault is not visible
//        o.methodPrivate();//The method methodPrivate() from the type Order is not visible
    }
}

二、构造器

  1、构造器的作用:

    1.1、创建对象

    1.2、初始化对象的属性

  2、说明

    2.1、如果没有显式的定义构造器的话,系统会默认提供一个空的构造器。

    2.2、定义构造器的格式:“”权限修饰符 类名(形参列表){}”。

    2.3、一个类中定义的多个构造器彼此构成重载。

    2.4、一旦显式的定义了构造器之后,系统就不再提供默认的空参构造器。为·

    2.5、一个类中至少有一个构造器。

  3、属性赋值先后顺序

    默认初始化  --》  显示初始化   --》  构造器赋值  --》  通过“对象.方法”或“对象.属性”的方式赋值

public class PersonTest {
    public static void main(String[] args) {
        //创建对象:new 构造器
        Person p = new Person();
        p.eat();
        
        //通过构造器初始化对象
        Person p1 = new Person("tom");
        System.out.println(p1.name);
    }
}

class Person {
    String name;
    int age;
    
    public Person() {
        System.out.println("Person...........");
    }
    
    
    public Person(String n) {
        name = n;
    }

    public void eat() {
        System.out.println("人吃饭");
    }
}

 三、this关键字

  1、this可以修饰属性、方法、构造器。

  2、this修饰属性和方法

    2.1、此时this可以理解为“当前对象”。

    2.2、在类的方法中,我们可以使用“this.属性”或“this.方法”的方式来调用当前对象的属性或方法。但是通常情况下选择省略“this.”。特殊情况下,如果方法的形参和类的属性同名,调用属性时必须使用“this.变量”的方式,表明此变量是属性,而非形参。

    2.3、在类的构造器中,我们可以使用“this.属性”或“this.方法”的方式来调用正在创建的对象属性或方法。但是通常情况下选择省略“this.”。特殊情况下,如果构造器的形参和类的属性同名,调用属性时必须使用“this.变量”的方式,表明此变量是属性,而非形参。

  3、this修饰构造器

    3.1、我们在类的构造器中,可以显式的使用“this(形参列表)”的方式,调用本类中指定的其他构造器。

    3.2、构造器中不能通过“this(形参列表)”的方式调用自身。

    3.3、如果一个类中有N个构造器,则最多有N-1个构造器使用“this(形参列表)”。

    3.4、规定“this(形参列表)”必须声明在当前构造器的首行。

    3.5、构造器内部最多只能声明一个“this(形参列表)”,用来调用其他构造器。

public class PersonTest {
    public static void main(String[] args) {
        Person p = new Person();
        p.setAge(10);
        System.out.println(p.getAge());

    }
}

class Person {
    private String name;
    private int age;
    private boolean isChild;

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

    public String getName() {
        return name;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public int getAge() {
        return age;
    }

    public Person() {

    }

    public Person(int age) {
        this.age = age;
        //通过this调用方法
        this.isChild(age);
    }

    public Person(String name) {
        this.name = name;
    }

    public Person(int age, String name) {
//        初始化时需要同时给姓名年龄赋值
        this(name);
        this.age = age;
    }

    public void isChild(int age) {
        if (age > 12) {
            isChild = false;
        } else {
            isChild = true;
        }
    }

}

 四、package关键字

  1、为了更好地实现类的管理,提出了包的概念。

  2、使用package声明类或接口所属的包。

  3、包名属于标识符,遵循标识符的命名规则、规范、“见名知意”。

  4、每“.”一次,代表一层文件目录。

  5、同一个包下,不能命名同名的接口、类。

     不同的包下,可以命名同名的接口、类。

  6、JDk主要的包:

    6.1、java.lang--------包含一些java语言的核心类,如String、Math、Integer、System、Thread,提供常用功能。

    6.2、java.net----------包含执行与网络相关的操作的类和接口。

    6.3、java.io------------包含能提供多种输入输出功能的类。

    6.4、java.util-----------包含一些实用工具类,如定义系统特性、集合框架、日期日历相关的函数。

    6.5、java.text----------包含了一些java格式化相关的类。

    6.6、java.sql-----------包含了java进行JDBC数据库编程的相关类、接口。

    6.7、java.awt----------包含了构成抽象窗口工具集的多个类,这些类被用来构建和管理应用程序的图形用户界面。

五、import关键字

  1、在源文件中显式的使用import结构导入指定包下的类、接口。

  2、声明在包的声明和类的声明之间。

  3、如果需要导入多个结构、则并列导入即可。

  4、可以使用“xxx.*”的方式导入包下所有类。

  5、如果使用的类和接口是“java.lang”包下定义的,则可以省略import结构。

  6、如果使用的类或接口是本包下定义的,则可以省略import关键字。

  7、如果在源文件中,使用了不同i包下的同名的类,则必须至少有一个需要以全类名(包含包名,例:com.oldking.model.User)的方式显式。

  8、如果使用“xxx.*”的方式,表明可以调用xxx包下的所有结构。但是如果使用的是xxx子包下的结构,则仍需要显式导入。

  9、import static:导入指定类或接口中的静态结构:属性或方法。

六、面向对象特征之二:继承性

  1、继承的好处

    1.1、减少了代码的冗余。

    1.2、便于功能扩展。

    1.3、位置后多态性使用提供前提。

  2、继承的格式:class A extends B{};

    2.1、A:子类、派生类、subclass

    2.2、B:父类、超类、基类、superclass

    2.3、体现:一旦子类A继承了父类B之后,子类A就父类B中声明的结构,属性,方法。

       特别的,父类中声明为private的属性或方法,子类继承父类以后,仍然认为获取了父类中私有的结构,只是因为封装的影响,是的子类不能直接调用父类的结构而已。

    2.4、子类继承父类以后,还可以声明自己特有的属性和方法,实现功能的拓展。

       子类和父类的关系不同于子集和集合的关系

  3、Java中关于继承性的规定

    3.1、一个类可以被多个子类继承。

    3.2、Java中类的单继承性:一个类只可以有一个父类。

    3.3、子类和父类是相对的概念。

    3.4、子类直接继承的父类称为:直接父类。间接继承的称为:间接父类。

    3.5、子类继承父类以后,就获取了直接父类以及所有间接父类中声明的属性和方法。

  4、Object类

    4.1、如果我们没有显式的声明一个类的父类的话,则此类继承于java.lang.Object类。

    4.2、所有的Java类(java.lang.Object类除外)都直接或间接的继承于java.lang.Object类。

    4.3、所有的Java类都具有java.lang.Object类声明的功能。

public class Person {
    String name;
    int age;

    public Person() {

    }

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
    
    
    
    public void eat() {
        System.out.println("吃饭");
    }
    
    public void sleep() {
        System.out.println("睡觉");
    }

}
public class Student extends Person {
    String major;

    public Student() {

    }

    public Student(String major, String name, int age) {
        this.major = major;
        this.name = name;
        this.age = age;
    }

    public void study() {
        System.out.println("学习");
    }

}
public class ExtendsTest {
    public static void main(String[] args) {
        Student s = new Student();
        s.eat();
        s.sleep();
        s.study();
    }
}

七、方法的重写

  1、重写:子类继承父类以后,可以对父类中的同名同参方法进行覆盖操作。

  2、应用:重写以后,当创建子类对象以后,通过子类对象调用子父类中的同名同参的方法时,实际执行的是子类重写父类的方法。

  3、重写的规定:

    3.1、子类重写的方法的方法名和形参列表,和父类中被重写的方法的方法名和形参列表相同。

    3.2、子类重写的方法的权限修饰符不得小于父类被重写的方法的权限修饰符。

    3.3、特殊情况:子类不能重写父类中声明为private权限的方法。

    3.4、返回值类型:

      3.4.1、父类的返回值类型是void,则子类重写的方法的返回值类型也只能是void。

      3.4.2、父类重写的方法的返回值是A类,则子类重写的方法的返回值类型可以是A类或A类的子类。

      3.4.3、父类重写的方法的返回值是基本数据类型,则子类重写的方法的返回值类型必须是相同的基本数据类型。

    3.5、子类重写的方法抛出的异常类型不大于父类被重写方法抛出的异常类型。

    3.6、子父类中的同名同参数方法,必修都声明为static(不是重写),或者都声明为非static(考虑重写)。

八、super关键字

  1、super:可理解为“父类的”。

  2、super可以用来调用父类的属性、方法、构造器。

  3、super的使用:

    3.1、我们可以在子类的方法或构造器中,通过“super.属性”或“super.方法”的方式,显式调用父类中的属性或方法,但是我们习惯省略“super”。

    3.2、特殊情况:当子类和父类中定义了同名的属性,我们在子类中调用父类中声明的属性时,则必须显式的使用“super.属性”的方式,表明调用的是父类中的属性。

    3.3、特殊情况:当子类重写了父类中的方法之后,我们想在子类的方法中调用父类中被重写的方法时,则必须显式的使用“super.方法”的方式,表明调用的是父类中被重写的方法。

九、super调用构造器

  1、我们可以在子类的构造器中显式的使用“super(形参列表)”的方式,调用父类中声明的指定构造器。

  2、“super(形参列表)”的使用,必须声明在子类构造器的首行。

  3、我们在类的构造器中,针对“this(形参列表)”和“super(形参列表)”只能二选一,不能同时出现。

  4、在构造器的首行,没有显式声明“this(形参列表)”或“super(形参列表)”,则默认调用父类的空参构造器“super()”。

public class Person {
    String name;
    int age;
    int id = 1001;

    public Person() {

    }

    public Person(String name) {
        this.name = name;
    }
    public Person(String name,int age) {
        this(name);
        this.age = age;
    }
    
    
    public void eat() {
        System.out.println("人吃饭");
    }
    public void walk() {
        System.out.println("人走路");
    }
    
    public void sleep() {
        System.out.println("睡觉");
    }

}
public class Student extends Person {
    String major;
    int id = 1002;// 学号

    public Student() {

    }

    public Student(String major) {
        this.major = major;
    }
    
    public Student(String major,String name,int age) {
//        this.name = name;
//        this.age = age;
        //如果父类属性为私有,则不可用上述方法赋值。
        super(name,age);//调用父类构造器
        this.major = major;
    }

    public void study() {
        System.out.println("学生:学习知识");//学生:学习知识
        this.eat();//学生,多吃点长个儿
        super.eat();//人吃饭

    }

    public void eat() {
        System.out.println("学生,多吃点长个儿");
    }

    public void show() {
        System.out.println("name = " + name + ",age = " + age);
        System.out.println("id = " + id);//id = 1002
        System.out.println("id = " + super.id);//id = 1001

    }

}

十、子类对象实例化过程

  1、从结果上看:

    1.1、子类继承了父类以后,就获取了父类中声明的属性或方法。

    1.2、创建子类的对象,在堆空间中,就会加载所有父类中声明的属性。

  2、从过程上看:

    1.1、当我们通过子类的构造器,创建子类对象时,我们一定会直接或间接的调用其父类的构造器,进而调用其祖先类的构造器,直到调用了java.lang.Object类中的空参构造器为止。正因为加载过所有的父类的结构,所以才可以看到内存中有父类中的结构,子类对象才可以考虑进行调用。

  3、虽然创建对象时调用了父类的构造器,但自始至终只创建了一个对象,即为new的子类对象。 

十一、面向对象特征之三:多态性

  1、理解多态:可以理解为一个事物的多种形态。

  2、何为多态:

      对象的多态性:父类的引用指向子类对象(或子类的对象赋给父类的引用)

  3、多态的使用:虚拟方法调用

    在编译期只能调用父类中声明的方法,但在运行期,我们实际执行的是子类重写父类的方法。

        总结:编译看左边,运行看右边。

  4、多态性使用前提

    4.1、存在类的继承关系。

    4.2、要有方法的重写。

  5、多态性只适用于方法,不适用于属性。

  6、有了对象的多态性以后,内存中实际上是加载了子类特有的属性和方法,但是由于变量声明为父类类型导致编译时只能调用父类中声明的属性和方法,子类特有的属性和方法不能调用。

  7、如何才能调用子类特有的属性和方法?

     使用强制类型转换符。

public class Person {
    String name;
    int age;
    int id = 1001;

    public void eat() {
        System.out.println("人:吃饭");

    }

    public void walk() {
        System.out.println("人;走路");
    }
}
public class Man extends Person {
    boolean isSmoking;
    int id = 1002;

    public void earnMoney() {
        System.out.println("男人负责挣钱养家");
    }

    public void eat() {
        System.out.println("男人:多吃肉");

    }

    public void walk() {
        System.out.println("男人霸气的走路");
    }
}
public class Woman extends Person {
    boolean isBeauty;

    public void goshoping() {
        System.out.println("女人喜欢购物");
    }

    public void eat() {
        System.out.println("女人少吃,减肥");

    }

    public void walk() {
        System.out.println("女人窈窕的走路");
    }
}
public class PersonTest {
    public static void main(String[] args) {
        Person p1 = new Person();
        p1.eat();
        Man man = new Man();
        man.eat();
        man.age = 25;
        man.earnMoney();

//        *************************************
        // 对象的多态性:父类信用指向子类对象
        Person p2 = new Man();
//        Person p3 = new Woman();
        // 当调用子父类同名同参数的方法时,实际执行的是子类重写父类的方法--------------------虚拟方法调用
        p2.eat();// 男人:多吃肉
        p2.walk();// 男人霸气的走路

//        p2.earnMoney();//The method earnMoney() is undefined for the type Person

        // 对象的多态性只适用于方法,不适用于属性。
        System.out.println(p2.id);// 1001

        p2.name = "Tom";
//        p2.isSmoking = true;
//        p2.earnMoney();
        // 有了对象的多态性以后,内存中实际上是加载了子类特有的属性和方法,但是由于变量声明为父类类型导致编译时
        // 只能调用父类中声明的属性和方法,子类特有的属性和方法不能调用。

        // 如何才能调用子类特有的属性和方法?
        //使用强制类型转换符。
        Man m1 = (Man) p2;

    }

}

十二、Object类

  1、Object类是所有Java类的根父类。

  2、如果未在类的声明中使用extends关键字指明其父类,则默认父类为java.lang.Object类。

  3、Object类中的功能(属性、方法)

    属性:无

    方法:equals()(对象比较)、toString()(打印对象)、getClass()、hashCode()、clon()、finalize()、wait()、notify()、notifyAll().........

  4、Object类只声明了一个空参构造器。

十三、“==”和“equals()”的区别

  1、==运算符

    1.1、可以使用在引用数据类型变量和基本数据类型变量中。

    1.2、如果比较的是基本数据类型变量,比较两个变量比较的数据是否相等(类型不一定要相同)。

       如果比较的是引用类型的变量,比较两个对象的地址值是否相同,即两个引用是否指向同一个对象实体。

  2、equals()方法的使用

    2.1、是一个方法,而非运算符。

    2.2、只适用于引用数据类型。

    2.3、Object类中equals()的定义:

        public boolean equals(Object obj){

        return (this == obj)

        }

      说明:Object类中定义的equals()方法和== 是相同的,比较的是两个对象的地址值是否相同,即两个引用是否指向同一个对象实体。

    2.4、像String 、Date、File、包装类等都重写了Object类中的equals()方法。重写以后比较的不再是两个引用的地址值是否相同,而是比较两个对象的“实体内容”是否相同。

    2.5、通常情况下,我们自定义的类如果使用equals()方法的话,也是比较两个对象的“实体内容”是否相同,那么我们就要对Object类中的equals()进行重写。

       重写的原则,比较两个对象的实体内容是否相同。

十四、包装类的使用

  1、Java提供了八种基本数据类型对应的包装类。使得基本数据类型的变量具有类的特征。

  2、基本数据类型、包装类、String 三者之间的相互转换。

    2.1、基本数据类型----》包装类:调用包装类的构造器。

    2.2、包装类--------》基本数据类型:调用包装类Xxx的xxxValue()方法。

    2.3、基本数据类型----------》String :

          方式1:x+‘’;   连接运算

          方式2: 调用String的valueOf(x); 

    2.4、String --------》基本数据类型、包装类:调用包装类的parseXxx(String s),可能会报NumberFromatException。

  3、JDK5.0新特性:自动装箱与自动拆箱。

    3.1、自动装箱    

public class Test {
    public static void main(String[] args) {
        int  num2 = 10;
        Integer in1 = num2;//自动装箱
        
        boolean b1 = true;
        Boolean b2 = b1;//自动装箱   
    }
}

    3.2、自动拆箱

public class Test {
    public static void main(String[] args) {
        Integer in1 = 10;
        int in2 = in1;//自动拆箱
        
        Boolean b1 = true;
        boolean b2 = b1;//自动拆箱
    }
    
    
}

 

    

    

posted @ 2021-03-15 22:46  早春的树  阅读(89)  评论(0)    收藏  举报