Java从零开始 基础(二)面向对象

创建类

  • java的建包标准是 域名倒过来,如域名:https://base.com
  • 在src下新建一个package,包名为:com.base
  • 在该包下新建两个java class,分别为Student,Application
  • 类是一个模板,对象是一个具体的实例

目录结构如下:

image-20210812125901548

创建对象

可以看到,在创建java class之后,会自动生成一个public class

Student.java:

package com.base;

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

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

Application.java: 实例化抽象类

package com.base;

// 一个项目应该只有一个main方法
public class Application {
    public static void main(String[] args) {
        // new Student() 实例化类 是一个动作
        // tom 实例化类后的具体实例,是一个对象
        Student tom = new Student();
        Student jack = new Student();

        // 给对象的属性赋值
        tom.name = "Tom";
        tom.age = 18;
        jack.name = "Jack";
        jack.age = 19;

        // 调用对象的方法
        tom.study();
        jack.study();
    }
}

构造器

概念

类似python的 __init__方法

一个类即使什么都没写,实际在编译成class文件后,也会生成一个 构造方法。如:

空类Student的class文件:

/.../
  
package com.base;

public class Student {
    public Student(){
    }
}

作用

显式定义构造方法

package com.base;

public class Student {
  	String name;
  
  	// 无参构造 
  	// 实例化初始值
  /*
    public Student(){
      this.name = "Tom";
    }
  */
  
    // 有参构造,在new Student时,必须传name参数
    public Student(String name){
      this.name = name;
    }
}

实现

改造一下上面的Student类

package com.base;

// 学生类
public class Student {
    String name;
    int age;

    // 构造方法
    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public void study(){
        System.out.println(this.name+"正在学习");
    }
}

在实例化Student时必须传name和age参数

package com.base;

public class Application {
    public static void main(String[] args) {
        Student tom = new Student("Tom", 18);
        Student jack = new Student("jack", 19);
    }
}

三大特性

封装

  • 数据的隐藏,仅暴露少量方法给外部调用
  • 通过接口来读写对象的数据(读写时可以判断)
  • 高内聚,低耦合
  • private、get、set
package com.base;

// 学生类
public class Student {
    // 属性
    public String name;  // 共有属性 
    private int age;  // 私有属性
    private char sex;

    // 提供可操作私有属性的方法
    // get 读
    public int getAge(){
      return this.age;
    }
    // set 写
    public void setAge(int age){
      this.age = age;
    }
}
package com.base;

public class Application {
    public static void main(String[] args) {
      Student tom = new Student();
      tom.name = "Tom";  // 共有属性可直接调用
      tom.setAge(18);  // 私有属性不能直接调用
      System.out.println(tom.getAge());
    }
}

继承

  • java只有单继承,没有多继承

  • 子类拥有父类所有的 public、protected 属性/方法

  • 所有类都有一个共同的父类 object,预置了一些方法

  • public:完全开放

  • protected 对同胞和子类开放,其他私有

  • default:对同胞开放,其他私有

  • private:完全私有

  • 实例化调用子类时,默认先调用父类的构造方法;super()只能出现在子类的方法

  • 调用父类构造方法,必须写在第一行

语法和特点

父类 Person:

package com.base;

// 父类
public class Person {
    String name;
    int age;
    char sex;
    public void say() {
        System.out.println(name + " 说了一句话");
    }
}

子类 Student:

快捷键:ctrl + h 打开继承树

package com.base;

// 子类(派生类)
public class Student extends Person {  // 继承语法

}

入口类 Application:

package com.base;

public class Application {
    public static void main(String[] args) {
        Student tom = new Student();
        tom.name= "Tom";  // Student类拥有person的属性和方法
        tom.say();
    }
}

super关键字

  • this:指代自己,类比python的self
  • super:指代父类

父类 Person:

package com.base;

// 父类
public class Person {
    protected String name = "Tom";
    public void eat(){
        System.out.println("父类的吃");
    }
}

子类 Student:

package com.base;

// 子类(派生类)
public class Student extends Person {
    private String name = "Jack";

    public void eat(){
        System.out.println("子类的吃");
    }

    public void getName(){
        String father_name = super.name;  // Tom
        String self_name = this.name;  // Jack
        super.eat();  // 父类的吃
        this.eat();  // 子类的吃
    }
}

方法重写

  • 有继承关系,子类重写父类的方法
  • 方法名必须相同、参数列表必须相同
  • 子类方法修饰关键字范围不能缩小(如:不能从public 到 protected)
  • 子类方法抛出异常范围只能缩小
  • 静态方法(static)只能被继承,不能被重写

父类 Person:

package com.base;

public class Person {
    public static void test(){
        System.out.println("Person");
    }
}

子类 Student:

package com.base;

public class Student extends Person {
    public static void test(){  // 重写父类test方法
        System.out.println("Student");
    }
}

入口 Applicaton:

package com.base;

public class Application {
    public static void main(String[] args) {
        Student s = new Student();
        s.test();  // Student

        // 父类的引用指向子类
        Person p = new Student();
        p.test();  // Person,如果去掉父/子类的static,这里就是Student
    }
}

多态

  • 功能:同一方法因饮用对象的不同而采用多种不同的行为方式(在子类重写父类的方法后,用父类的引用来new子类的对象,调用该方法,执行的是子类的方法)
  • 要求:有继承关系,子类重写父类方法
  • 使用:父类引用指向子类对象:Person Tom = new Student();
  • 错误:父类引用调用子类独有的方法:ClassCaseException异常
  • 转换:父类引用可以通过强制转换来调用子类独有的方法
  • 注意:多态是方法的多态,属性没有多态

父类 Person:

package com.base;

// 父类
public class Person {
    public void test(){
        System.out.println("Person");
    }
}

子类 Student:

package com.base;

public class Student extends Person {
    @Override
    public void test() {  // 重写父类方法
        System.out.println("Student");
    }

    public void eat(){  // 父类没有的方法
        System.out.println("Student");
    }
}

入口 Application:

package com.base;

public class Application {
    public static void main(String[] args) {
        Student s = new Student();
        Person p = new Student();
        Object o = new Student();
      	Student stu = new Person();  // 报错 子类引用无法指向父类对象
      
      	// 判断两边是否有继承关系,左实例 右类
      	System.out.println(o instanceof Student);
        System.out.println(o instanceof Person);
        System.out.println(p instanceof Student);

        s.test();  // Student  子类可以调用自己和父类的方法
        p.test();  // Student  父类可以调用子类重写的方法,不能调用子类独有的方法
        o.test();  // 报错  父类调用子类独有的方法

        s.eat();  // student
        p.eat();  // 报错
        o.eat();  // 报错
      
      	((Student) o).test();  // Student  通过强制转换来调用子类独有的方法
      	((Student) p).eat();  // Student  
      	((Student) o).eat();  // Student
    }
}

static 修饰

static修饰的变量/方法,和类一起加载,可以直接调用

package com.base;

// 父类
public class Person {
    static int age=10;  // 静态变量
    int num=5;  // 非静态变量

    public static void age(){  // 静态方法
        System.out.println("age");
    }

    public void num(){  // 非静态方法
        System.out.println("num");
    }


    public static void main(String[] args) {
        int a = age;  // 静态变量可以直接使用
        age();  // 静态方法可直接调用
        
      	int n = num;  // 非静态方法不能直接使用,报错
				num();  // 报错
      
        Person person = new Person();  // 非静态方法在实例化后调用
        int p = person.num;
        person.num();
      
    }
}

执行顺序

静态代码块 -> 匿名代码块 -> 构造方法

package com.base;

// 父类
public class Person {
    {
        System.out.println("匿名代码块");
    }
    static {
        System.out.println("静态代码块");  // 只执行一次
    }

    public Person() {
        System.out.println("构造方法");
    }

    public static void main(String[] args) {
        Person p = new Person();
    }
}
image-20210812181807026

抽象类

  • 抽象类:用abstract声明的类;不能new,只能继承,起到约束作用;
  • 抽象方法:用abstract声明的方法;抽象方法只能写在抽象类中;只有方法名,没有方法体;非抽象类的子类必须实现父类的抽象方法;

父类(抽象类)Person:

package com.base;

public abstract class Person {
    // 抽象方法,只有方法名,没有方法体
    public abstract void someThing();

    public void eat() {
        System.out.println("Eat");
    }
}

子类 Student:

package com.base;

public class Student extends Person {
    @Override
    public void someThing() {  // 重写父类的抽象方法(必须重写)
        System.out.println("你好");
    }
}

接口

  • 关键字:interface
  • java的类只能单继承,但接口可以多继承
  • 接口就是规则,定义好接口之后,让不同的类来实现
  • 接口的方法只能是方法,只写方法名,不写方法体
  • 只能继承,不能new,没有构造方法;继承之后必须重写接口的方法

接口定义 UserService:

package com.object;

// 使用interface关键字定义接口
// 接口一般都有实现类,实现类以Impl结尾
public interface UserService {
    // 接口中所有属性都是常量,默认加上了 public static final
    int AGE=99;

    // 接口中的所有方法都是抽象的,默认加上了abstract
    void addUser(String name);
    void delUser(String name);
}

实现类 UserServiceImpl:

package com.object;

// 接口的实现类 关键字:implements
// 继承多个接口用逗号隔开
// 必须重写接口中的方法
public class UserServiceImpl implements UserService, TimeService{
    @Override
    public void addUser(String name) {

    }

    @Override
    public void delUser(String name) {

    }

    @Override
    public void time() {

    }
}

内部类

在类的里面再定义一个类,包括:成员/静态/局部/匿名 内部类

成员内部类

package com.local;

public class OutSide {  // 外部类
    int a = 10;
  
  	// 成员内部类
    public class Inner{
        public void insideMethod(){
            System.out.println(a);  // 内部类可直接访问外部类的属性
        }
    }
}

class run{
    public static void main(String[] args) {
        OutSide out = new OutSide();
        OutSide.Inner inner = out.new Inner();
        inner.insideMethod();
    }
}

静态内部类

package com.local;

public class OutSide {  // 外部类
    int a = 10;
  
  	// 静态内部类
    public static class Inner{  
        public void insideMethod(){
            System.out.println(a);  // 报错,加上static后无法访问外部类属性,因为static先实例化,实例化这个内部类的时候,a属性还没实例化
        }
    }
}

class run{
    public static void main(String[] args) {
        OutSide out = new OutSide();
        OutSide.Inner inner = out.new Inner();
        inner.insideMethod();
    }
}

局部内部类和匿名内部类

package com.local;

public class OutSide {  // 外部类
    int a = 10;

    public void method(){  // 方法
        // 局部内部类
        class Inner{
            public void insideMethod(){
                System.out.println(a);
            }
        }
        new Inner().insideMethod();  // 匿名内部类,直接new完调方法,不用存到变量
    }
}

class run{
    public static void main(String[] args) {
        OutSide out = new OutSide();
        out.method();

    }
}
posted @ 2021-08-13 09:55  寡淡的白开水  阅读(63)  评论(0)    收藏  举报