Java面向对象

Java面向对象

面向过程&面向对象

面向过程:

  • 步骤清晰简单,第一步做什么,第二步做什么……
  • 面向过程适合处理一些较为简单的事情

面向对象:

  • 物以类聚,分类的思维模式。思考问题首先会解决问题需要哪些分类,然后对这些分类进行单独思考。最后,才对某个分类下的细节进行面向过程的思索。
  • 面向对象适合处理复杂的问题,适合处理需要多人协作的问题。

概述:对于描述复杂的事物,为了从宏观上把握、从整体上合理分析,我们需要使用面向对象的思路来分析整个系统。但是,具体到微观操作,仍然需要面向过程的思路去处理。

什么是面向对象?

面向对象(Object-Oriented Programming, OOP)的本质是以的方式组织代码,以对象的方式封装数据

三大特性:

  • 封装
  • 继承
  • 多态

注意:

  • 从认识论的角度考虑,是先有对象后有类。因为对象是具体的,而类是抽象的。类是对对象的抽象。
  • 从代码运行的角度考虑,是先有类后有对象。类是对象的模板。

类与对象的关系

是一种抽象的数据类型。它是对某一类事物的整体描述或定义,但并不能代表某一个具体的事物。

  • 如:人、动物、植物、电脑、手机,等等……

对象是抽象概念的具体实例

  • 如:张三、隔壁家的小花猫咪咪、《唐伯虎点秋香》里的那只名叫旺财的狗

初始化与创建对象

创建的方式:使用new关键字创建对象

使用new关键字创建对象的时候,除了分配内存空间之外,还会给创建好的对象赋默认值进行初始化,以及调用类中的构造器

示例:

Student类

package com.wmwx.oop.Demo01;

//学生类
public class Student {
    //属性:字段
    String name;
    int age;

    //方法
    public void study(){
        System.out.println("学生"+this.name+"在学习。");
    }
}

Application类(启动类)

package com.wmwx.oop.Demo01;

//启动类
public class Application {
    //一个项目应该只存在一个main方法
    public static void main(String[] args) {
        //类是抽象的,需要实例化
        //类实例化后会返回一个自己的对象
        //student对象是Student类的一个实例
        Student student = new Student();
        student.study();        //输出"学生null在学习。"
        student.name = "小明";
        student.study();        //输出"学生小明在学习。"
    }
}

构造方法

当一个对象被创建时候,构造方法用来初始化该对象。构造方法和它所在类的名字相同,但构造方法没有返回值

一个类即使什么都不写,也会存在一个构造方法。因为 Java 自动提供了一个默认构造方法,其访问修饰符和类的访问修饰符相同。

一旦自己定义了构造方法,默认的构造方法就会失效。

示例:

Person类:

package com.wmwx.oop.Demo01;

public class Person {
    String name;
    //使用快捷键alt+insert可以自动生成构造方法
    //无参构造
    public Person(){
        this.name = "一个无名氏";
    }

    //有参构造(一旦定义有参构造,就必须显式定义无参构造)
    public Person(String name){
        this.name = name;
    }
}

Application类:

package com.wmwx.oop.Demo01;

public class Application {
    public static void main(String[] args) {
        //使用new关键字,本质是在调用构造方法
        Person person1 = new Person();                      //调用无参构造
        System.out.println(person1.name);                   //输出"一个无名氏"
        //利用构造方法,可以初始化对象
        Person person2 = new Person("惟妙惟霄");       		 //调用有参构造
        System.out.println(person2.name);                   //输出"惟妙惟霄"
    }
}

内存分析

过程如下:

  1. 创建类
  2. 在堆中存放类和类中的静态方法
  3. 创建对象
  4. 在堆中为对象开辟空间
  5. 在栈中存放对象的引用变量名
  6. 令对象的引用变量名指向堆中开辟的空间

封装

所谓封装,即该露的露,该藏的藏。程序设计要追求“高内聚,低耦合”

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

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

对于代码而言,总结起来就一句话:属性私有,get/set。

意义:

  • 提升程序的安全性,保护数据
  • 隐藏代码的实现细节
  • 统一接口
  • 提高了系统的可维护性

示例:

Student类:

package com.wmwx.oop.Demo03;

public class Student {
    //属性私有
    private String name;
    private int id;
    private String gender;
    private int age;

    //需要提供共有的get和set方法
    //get方法:获取数据
    public String getName() {
        return name;
    }
    //set方法:设置数据
    public void setName(String name) {
        this.name = name;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getGender() {
        return gender;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        if (age<0||age>120){
            this.age = 3;
        }else{
            this.age = age;
        }
    }
}

Application类:

package com.wmwx.oop;

import com.wmwx.oop.Demo03.Student;

//启动类
public class Application {
    public static void main(String[] args) {
        Student student = new Student();
        student.setName("惟妙惟霄");
        student.setId(123456);
        student.setGender("男");
        student.setAge(130);
        System.out.println(student.getAge());   //输出3
    }
}

继承

继承的本质是对某一批类的抽象,从而实现对现实世界更好的建模。

在 Java 中通过 extends 关键字可以声明一个类是从另外一个类继承而来的,其语法如下:

class 子类 extends 父类 {
}

extends的意思是扩展,子类是对父类的扩展

继承的注意事项:

  • Java只有单继承,没有多继承。

  • 在Java中,所有类都默认直接或间接继承自Object类

在Java中,可以使用this指代当前类,并使用super指代父类

super的注意事项:

  • super调用父类的构造方法,必须在构造方法的第一行
  • super只能出现在子类的方法或构造方法中。
  • super和this不能同时调用构造方法。

重写是子类对父类的允许访问的方法的实现过程进行重新编写, 返回值和形参都不能改变。重写的好处在于子类可以根据需要,定义特定于自己的行为。 也就是说,子类能够根据需要实现父类的方法。重写需要遵守以下规则:

  • 方法名必须相同
  • 参数列表必须相同
  • 修饰符的范围可以扩大,但不能缩小
  • 抛出的异常可以被缩小,但不能扩大

示例:

Person类:

package com.wmwx.oop.Demo04;

//父类:人类
public class Person {
    private int money = 10_0000_0000;
    protected String name = "惟妙惟霄";

    public Person() {
        System.out.println("Person的无参构造方法执行了!");
    }

    public void say(){
        System.out.println("说了一句话。");
    }

    public int getMoney() {
        return money;
    }

    public void setMoney(int money) {
        this.money = money;
    }

    public void print(){
        System.out.println("Person");
    }
}

Student类:

package com.wmwx.oop.Demo04;

//子类:学生类
public class Student extends Person{
    private String name = "妙霄";

    public Student() {
        //隐藏代码:super();
        //父类的构造方法必须要在子类的构造方法的第一行
        System.out.println("Student的无参构造方法执行了!");
    }

    public void test1(String name){
        System.out.println(name);           //输出参数
        System.out.println(this.name);      //输出当前类的name
        System.out.println(super.name);     //输出父类的name
    }

    //重写都是方法的重写,与属性无关
    //只允许重写public方法
    //可以使用快捷键alt+insert来插入重写方法
    @Override
    public void print() {
        System.out.println("Student");
    }

    public void test2(){
        print();
        this.print();
        super.print();
    }
}

Application类:

package com.wmwx.oop;

import com.wmwx.oop.Demo04.Person;
import com.wmwx.oop.Demo04.Student;

//启动类
public class Application {
    public static void main(String[] args) {
        Student student = new Student();
        //第一行输出"Person的无参构造方法执行了!"
        //第二行输出"Student的无参构造方法执行了!"
        student.say();      //子类继承父类,就会拥有父类的public方法
        System.out.println(student.getMoney()); //可以用父类的get/set方法对属性进行操作
        //可以使用快捷键ctrl+H来查看继承树
        student.test1("MiaoXiao");
        //第一行输出"MiaoXiao"
        //第二行输出"妙霄"
        //第三行输出"惟妙惟霄"
        student.test2();
        //第一行输出"Student"
        //第二行输出"Student"
        //第三行输出"Person"
        Student stu1 = new Student();
        stu1.print();   //输出"Student"
        //父类的引用指向了子类
        Person stu2 = new Student();
        stu2.print();   //输出"Student"
    }
}

多态

多态是同一个行为具有多个不同表现形式或形态的能力。当使用多态方式调用方法时,首先检查父类中是否有该方法,如果没有,则编译错误;如果,再去调用子类的同名方法。

多态存在的三个必要条件

  • 继承
  • 重写
  • 父类引用指向子类对象:Parent p = new Child();

不能被重写的方法:

  • static 方法
  • final 方法
  • private 方法

示例:

Person类:

package com.wmwx.oop.Demo05;

public class Person {
    public void run(){
        System.out.println("人在跑步。");
    }
}

Student类:

package com.wmwx.oop.Demo05;

public class Student extends Person{
    @Override
    public void run() {
        System.out.println("学生在跑步。");
    }

    public void eat(){
        System.out.println("学生在吃东西。");
    }
}

Application类:

package com.wmwx.oop;

import com.wmwx.oop.Demo05.Person;
import com.wmwx.oop.Demo05.Student;

//启动类
public class Application {
    public static void main(String[] args) {
        //一个对象的实际类型是确定的
        //但可以指向的引用类型是不确定的
        Student s1 = new Student();
        Person s2 = new Student();      //父类的引用指向子类
        Object s3 = new Student();
        s1.run();       //输出"学生在跑步"
        s2.run();       //子类重写父类方法,将执行子类方法,输出"学生在跑步。"
        s1.eat();       //输出"学生在吃东西"
        //s2.eat();     //不能调用。对象能使用哪些方法,要看左边的类型。
        ((Student)s2).eat();    //强制类型转换。输出"学生在吃东西。"
    }
}

instanceof

Java中的instanceof关键字可以用来判断某一个对象是不是某一个类是实例。如果是,返回true;如果不是,返回false;如果二者无关,则编译不通过。

示例:

package com.wmwx.oop;

import com.wmwx.oop.Demo06.Person;
import com.wmwx.oop.Demo06.Student;
import com.wmwx.oop.Demo06.Teacher;

//启动类
public class Application {
    public static void main(String[] args) {
        //继承关系如下:
        //Object -> Person -> Student
        //Object -> Person -> Teacher
        //Object -> String
        Object object = new Student();
        System.out.println(object instanceof Student);  //输出true
        System.out.println(object instanceof Person);   //输出true
        System.out.println(object instanceof Object);   //输出true
        System.out.println(object instanceof Teacher);  //输出false
        System.out.println(object instanceof String);   //输出false
        System.out.println("=====");
        Person person = new Student();
        System.out.println(person instanceof Student);  //输出true
        System.out.println(person instanceof Person);   //输出true
        System.out.println(person instanceof Object);   //输出true
        System.out.println(person instanceof Teacher);  //输出false
        //System.out.println(person instanceof String); //编译时报错
        System.out.println("=====");
        Student student = new Student();
        System.out.println(student instanceof Student);  //输出true
        System.out.println(student instanceof Person);   //输出true
        System.out.println(student instanceof Object);   //输出true
        //System.out.println(student instanceof Teacher);//编译时报错
        //System.out.println(student instanceof String); //编译时报错
    }
}

类型转换

  • 子类转换为父类,是向转型,可自动转换。
  • 父类转换为子类,是向转型,需强制转换。

示例:

Person类:

package com.wmwx.oop.Demo06;

public class Person {
    public void run(){
        System.out.println("人在跑步。");
    }
}

Student类:

package com.wmwx.oop.Demo06;

public class Student extends Person{
    public void walk(){
        System.out.println("学生在走路。");
    }
}

Application类:

package com.wmwx.oop;

import com.wmwx.oop.Demo06.Person;
import com.wmwx.oop.Demo06.Student;

//启动类
public class Application {
    public static void main(String[] args) {
        //高 ----------------- 低
        Person person = new Student();
        ((Student)person).walk();   //强制类型转换

        Student student = new Student();
        Person obj = student;       //子类转换为父类,可能会丢失一些方法
        //obj.walk();               //编译时报错
    }
}

静态代码块

静态代码块会在类加载时执行,且只会执行一次。

示例:

Person类:

package com.wmwx.oop.Demo07;

public class Person {
    //第二个执行,可在这里赋初始值
    {
        System.out.println("匿名代码块");
    }

    //第一个执行,只执行一次
    static {
        System.out.println("静态代码块");
    }

    //第三个执行
    public Person() {
        System.out.println("构造方法");
    }
}

Application类:

package com.wmwx.oop;

import com.wmwx.oop.Demo07.Person;

//启动类
public class Application {
    public static void main(String[] args) {
        Person person = new Person();
        //第一行输出"静态代码块"
        //第二行输出"匿名代码块"
        //第三行输出"构造方法"
    }
}

抽象类

在Java语言中使用abstract 来定义抽象类,其基本语法如下:

abstract class 类名{
    //属性
    //方法
}

抽象类除了不能实例化对象之外,类的其它功能依然存在,成员变量、成员方法和构造方法的访问方式和普通类一样。

由于抽象类不能实例化对象,所以抽象类必须被继承,才能被使用。在Java中一个类只能继承一个抽象类,但一个类可以实现多个接口

在Java语言中使用abstract 来定义抽象方法,其基本语法如下:

abstract 访问修饰符 返回值类型 方法名(参数);

抽象类与抽象方法的规则:

  • 抽象类不能被实例化(即不能被 new ),只有抽象类的非抽象子类可以创建对象。
  • 抽象类中不一定包含抽象方法,但是有抽象方法的类必定是抽象类。
  • 抽象类中的抽象方法只是声明,不包含方法体,也就是不给出方法的具体实现。
  • 构造方法、类方法(用 static 修饰的方法)不能声明为抽象方法。
  • 抽象类的子类必须给出抽象类中的抽象方法的具体实现,除非该子类也是抽象类

示例:

Action类:

package com.wmwx.oop.Demo08;

//使用abstract声明抽象类
public abstract class Action {
    //抽象方法,只有方法名,没有方法体
    //仅作约束,期待他人实现
    public abstract void doSomething();
}

A类:

package com.wmwx.oop.Demo08;

public class A extends Action{
    //子类必须实现父类的抽象方法
    //除非该子类是抽象类
    @Override
    public void doSomething() {

    }
}

接口

接口在JAVA编程语言中是一个抽象类型,是抽象方法的集合,通常以 interface 来声明。其基本语法如下:

[访问修饰符] interface 接口名称 [extends 其他的接口名称] {
        // 抽象方法
}

接口的特性:

  • 接口中每一个方法都是隐式抽象的,接口中的方法会被隐式地指定为 public abstract,并且只能是 public abstract。
  • 接口中可以含有变量,但是接口中的变量会被隐式地指定为 public static final ,并且只能是 public static final。
  • 接口中的方法不能在接口中实现,只能由实现接口的来实现接口中的方法。
  • 一个接口能继承另一个接口,使用 extends 关键字.子接口会继承父接口的方法。

当类实现接口的时候,需要实现接口中所有的方法。否则,类必须声明为抽象的类。Java中使用 implements 关键字实现接口,其基本语法如下:

class 类名 implements 方法名{
    //实现接口中的抽象方法
}

示例:

UserService接口:

package com.wmwx.oop.Demo09;

//定义接口使用关键字interface
public interface UserService {
    //接口中的所有属性都是public static final
    //一般不在接口中定义属性
    int age = 60;

    //接口中的所有方法都是public abstract
    void add(String name);
    void delete(String name);
    void update(String name);
    void query(String name);
}

TimeService接口:

package com.wmwx.oop.Demo09;

public interface TimeService {
    void timer();
}

UserServiceImpl类:

package com.wmwx.oop.Demo09;

//类使用关键字implements来实现接口
//实现了接口的类,需要重写接口的所有方法
//一个类可以实现多个接口
public class UserServiceImpl implements UserService, TimeService{

    @Override
    public void add(String name) {

    }

    @Override
    public void delete(String name) {

    }

    @Override
    public void update(String name) {

    }

    @Override
    public void query(String name) {

    }

    @Override
    public void timer() {

    }
}

内部类

所谓内部类,就是在一个类的内部再定义一个类。

示例:

Outer类:

package com.wmwx.oop.Demo10;

//外部类
public class Outer {
    private int id=10;
    public void out(){
        System.out.println("这是外部类的方法!");
    }

    public class Inner{
        public void in(){
            System.out.println("这是内部类的方法!");
        }

        //获得外部类的私有属性
        public int getId(){
            return id;
        }
    }

    public void method(){
        //局部内部类,在外部类的方法之中
        class Inner{

        }
    }
}

//一个java文件可以有多个class,但是只能有一个public class
class A{

}

Application类:

package com.wmwx.oop;

import com.wmwx.oop.Demo09.UserService;
import com.wmwx.oop.Demo10.Outer;

//启动类
public class Application {
    public static void main(String[] args) {
        //外部类使用new关键字
        Outer outer = new Outer();
        outer.out();
        //内部类通过外部类来实例化
        Outer.Inner inner = outer.new Inner();
        inner.in();
        System.out.println(inner.getId());
        //匿名类,不用将实例保存到变量中
        new Outer().out();
        //使用匿名类实现接口
        UserService userService = new UserService() {
            @Override
            public void add(String name) {

            }

            @Override
            public void delete(String name) {

            }

            @Override
            public void update(String name) {

            }

            @Override
            public void query(String name) {

            }
        }
    }
}
Tags: