java学习笔记(四、面对对象的定义)

本文介绍了Java中的类与对象的概念,包括如何创建类、实例化对象、使用构造方法以及访问控制。讨论了封装、继承、多态等面向对象编程的核心概念,并举例说明了抽象类和接口的使用。此外,还涉及到了枚举类的创建和使用。
摘要由CSDN通过智能技术生成

类与对象的定义:

类:一种类 事物类,比如说:人类

对象:一种类的具体的对象,比如说具体到哪个人:lbw

在源文件src中创建Main类,右键src,命名记得首字母要大写

类中可以 定义一些变量

public class Main {
    String name="li";
    int age=18;
    String sex="nan";
}

有时会报错:

记得构造项目(就是按一下锤子)

解决方法:如图

没有问题后:

new关键词 就是新建一个Main的对象 命名为main

语法就是这一句:

Main main=new Main();

利用.语法进行对对象内的值进行调用

public class Main1 {
    public static void main(String[] args) {
        Main main=new Main();
        System.out.println(main.name);
    }
}

方法:

和C语言中的函数一样

返回值 方法名称(){

方法体

}

返回值可以是void int Srting double等等

方法名称随意与变量一致 不过小写字母好点

void:没有返回值 就是不用return的意思

如果有返回值的话 就要return对应的返回值否则就会报错

public class Main {
    String name="li";
    int age=18;
    String sex="nan";
    void hello(){
        System.out.println("我叫 "+name+" 今年 "+age+" 岁了!");
    }
    int sum(int a, int b){   //这里的参数,相当于我们在函数中定义了两个局部变量,我们可以直接在函数中使用
        int c = a + b;   //直接c = a + b
        return c;
    }
    void setName(String name) {
        this.name = name;   //让当前对象的name变量值等于参数传入的值
    }
}

public class Main1 {
    public static void main(String[] args) {
        Main main=new Main();
        System.out.println(main.sum(1, 2));
        main.hello();
    }
}

this:

当出现重名时 this用来针对对象本身=右边的name就是String name方法引入的name

=的左边就是对象中的name 即String name="li";

方法的重载:

有些时候,参数类型可能会多种多样,我们的方法需要能够同时应对多种情况:

这种多情况会自适应选择调用

int sum(int a, int b){
    return a + b;
}

double sum(double a, double b){    //为了支持小数加法,我们可以进行一次重载
    return a + b;
}

方法对自己的调用(递归)

int test(int n){
    if(n == 0) return 0;
    return test(n - 1) + n;    //返回的结果是下一层返回的结果+当前这一层的n
}

构造方法:

构造方法不需要填写返回值,并且方法名称与类名相同

就是有个默认的构造方法new 当然也可以自己写一个构造方法

(没必要不如用new)直接Person p = new Person("小明", 18, "男");就行

public class Person {
    String name;
    int age;
    String sex;

    public Person() {    //反编译中,多出来了这样一个方法,这其实就是构造方法
    }
}

public static void main(String[] args) {
    Person p = new Person();   //这里的new Person()其实就是在调用无参构造方法
    System.out.println(p.name);
}

public class Person {
    String name;
    int age;
    String sex;

    Person(String name, int age, String sex){   //跟普通方法是一样的
        this.name = name;
        this.age = age;
        this.sex = sex;
    }
}

public static void main(String[] args) {
    Person p = new Person("小明", 18, "男");   //调用自己定义的带三个参数的构造方法
    System.out.println(p.name);
}

静态变量和静态方法:

(全局都不改变的值) 因为静态方法属于类的,所以说我们在静态方法中,无法获取成员变量的值

同样的,在静态方法中,无法使用this关键字,因为this关键字代表的是当前的对象本身

但是静态方法是可以访问到静态变量的

静态变量的构造在代码之前

static String info;    //这里我们定义一个info静态变量


static void test(){
    System.out.println("我是静态方法");
}

public class Person {
    String name = test();  //这里我们用test方法的返回值作为变量的初始值,便于观察
    int age;
    String sex;

    {
        System.out.println("我是普通代码块");
    }
    
    Person(){
        System.out.println("我是构造方法");
    }
    
    String test(){
        System.out.println("我是成员变量初始化");
        return "小明";
    }

    static String info = init();   //这里我们用init静态方法的返回值作为变量的初始值,便于观察

    static {
        System.out.println("我是静态代码块");
    }

    static String init(){
        System.out.println("我是静态变量初始化");
        return "test";
    }
}

包和访问控制:

包:

import导包

package 用自己的包

最常见的import java.io.*;

package com.test;

import com.test.entity.Person;   //使用import关键字导入其他包中的类

import java.io.*;

public class Main {
    public static void main(String[] args) {
        Person person = new Person();   //只有导入之后才可以使用,否则编译器不知道这个类从哪来的
    }
}

访问权限控制:

当前类

同一个包下的类

不同包下的子类

不同包下的类

public

protected

默认

private

封装、继承、多态、抽象类、接口:

封装:

封装的目的是为了保证变量的安全性,使用者不必在意具体实现细节,而只是通过外部接口即可访问类的成员,如果不进行封装,类中的实例变量可以直接查看和修改,可能给整个代码带来不好的影响,因此在编写类时一般将成员变量私有化,外部类需要使用Getter和Setter方法来查看和设置变量。

public class Person {
    private String name;    //现在类的属性只能被自己直接访问
    private int age;
    private String sex;
    public Person(String name, int age, String sex) {   //构造方法也要声明为公共,否则对象都构造不了
        this.name = name;
        this.age = age;
        this.sex = sex;
}

    public String getName() {
        return name;    //想要知道这个对象的名字,必须通过getName()方法来获取,并且得到的只是名字值,外部无法修改
    }

    public String getSex() {
        return sex;
    }

    public int getAge() {
        return age;
    }
}

public static void main(String[] args) {
    Person person = new Person("小明", 18, "男");
    System.out.println(person.getName());    //只能通过调用getName()方法来获取名字
}

继承:

extends:

使用extends后 子类可以有父类的变量和方法

final 不可以被继承

当一个类继承另一个类时,属性会被继承,可以直接访问父类中定义的属性,除非父类中将属性的访问权限修改为

private,那么子类将无法访问(但是依然是继承了这个属性的):

public class Worker extends Person{    //工人类

}
public final class Person {  //class前面添加final关键字表示这个类已经是最终形态,不能继承
  
}
public class Person {
    String name;
    int age;
    String sex;

    public void hello(){
        System.out.println("我叫 "+name+",今年 "+age+" 岁了!");
    }
}
public class Student extends Person{
    public void study(){
        System.out.println("我的名字是 "+name+",我在学习!");   //可以直接访问父类中定义的name属性
    }
}
public static void main(String[] args) {
    Student student = new Student();
    student.study();    //子类不仅有自己的独特技能
    student.hello();    //还继承了父类的全部技能
}
public class Student extends Person{
    public Student(String name, int age, String sex) {    //因为学生职业已经确定,所以说学生直接填写就可以了
        super(name, age, sex, "学生");   //使用super代表父类,父类的构造方法就是super()
    }
    public void study(){
        System.out.println("我的名字是 "+name+",我在学习!");
    }
}
public class Worker extends Person{
    public Worker(String name, int age, String sex) {
        super(name, age, sex, "工人");    //父类构造调用必须在最前面
        System.out.println("工人构造成功!");    //注意,在调用父类构造方法之前,不允许执行任何代码,只能在之后执行
    }
}
public static void main(String[] args) {
    Person person = new Student("小明", 18, "男");    //这里使用父类类型的变量,去引用一个子类对象(向上转型)
    person.hello();    //父类对象的引用相当于当做父类来使用,只能访问父类对象的内容
}
public static void main(String[] args) {
    Person person = new Student("小明", 18, "男");
    Student student = (Student) person;   //使用强制类型转换(向下转型)
    student.study();
}
public static void main(String[] args) {
    Person person = new Worker("小明", 18, "男");   //实际创建的是Work类型的对象
    Student student = (Student) person;
    student.study();
}
public void work(){
    System.out.println("我是 "+super.name+",我在工作!");   //这里使用super.name来表示需要的是父类的name变量
}
public static void main(String[] args) {
    Person person = new Student("小明", 18, "男");
    if(person instanceof Student) {   //我们可以使用instanceof关键字来对类型进行判断
        System.out.println("对象是 Student 类型的");
    }
    if(person instanceof Person) {
        System.out.println("对象是 Person 类型的");
    }
}

虽然我们这里使用的是父类类型引用的对象,但是这并不代表子类就彻底变成父类了,这里仅仅只是当做父类使用而已。

我们也可以使用强制类型转换,将一个被当做父类使用的子类对象,转换回子类:

但是注意,这种方式只适用于这个对象本身就是对应的子类才可以,如果本身都不是这个子类,或者说就是父类,那么会出现问题:

那么,在子类存在同名变量的情况下,怎么去访问父类的呢?我们同样可以使用super关键字来表示父类

如果变量所引用的对象是对应类型或是对应类型的子类,那么instanceof都会返回true,否则返回false。

实际上所有类都默认继承自Object类,除非手动指定继承的类型,但是依然改变不了最顶层的父类是Object类。

方法的重写:

这其实就是面向对象编程中多态特性的一种体现。

注意,方法的重写不同于之前的方法重载,不要搞混了,方法的重载是为某个方法提供更多种类,而方法的重写是覆盖原有的方法实现,比如我们现在不希望使用Object类中提供的equals方法,那么我们就可以将其重写了

public class Person{
    @Override   //重写方法可以添加 @Override 注解,有关注解我们会在最后一章进行介绍,这个注解默认情况下可以省略
    public boolean equals(Object obj) {   //重写方法要求与父类的定义完全一致
        if(obj == null) return false;       //如果传入的对象为null,那肯定不相等
        if(obj instanceof Person) {     //只有是当前类型的对象,才能进行比较,要是都不是这个类型还比什么
            Person person = (Person) obj;   //先转换为当前类型,接着我们对三个属性挨个进行比较
            return this.name.equals(person.name) &&    //字符串内容的比较,不能使用==,必须使用equals方法
                    this.age == person.age &&       //基本类型的比较跟之前一样,直接==
                    this.sex.equals(person.sex);
        }
        return false;
    }
}
public static void main(String[] args) {
    Person p1 = new Student("小明", 18, "男");
    Person p2 = new Student("小明", 18, "男");
    System.out.println(p1.equals(p2));   //此时由于三个属性完全一致,所以说判断结果为真,即使是两个不同的对象
}

有时候为了方便查看对象的各个属性,我们可以将Object类提供的toString方法重写了:

注意,静态方法不支持重写,因为它是属于类本身的,但是它可以被继承。

@Override
public String toString() {    //使用IDEA可以快速生成
    return "Person{" +
            "name='" + name + '\'' +
            ", age=" + age +
            ", sex='" + sex + '\'' +
            ", profession='" + profession + '\'' +
            '}';
}
public static void main(String[] args) {
    Person person = new Student("小明", 18, "男");
    System.out.println(person);
}

基于这种方法可以重写的特性,对于一个类定义的行为,不同的子类可以出现不同的行为,比如考试,学生考试可以得到A,而工人去考试只能得到D:

public class Person {
    ...   


    public void exam(){
        System.out.println("我是考试方法");
    }
  
      
}
public class Student extends Person{ 
    ...  
    @Override
    public void exam() {
        System.out.println("我是学生,我就是小镇做题家,拿个 A 轻轻松松");
    }
}
public class Worker extends Person{
  
    ...

    @Override
    public void exam() {
        System.out.println("我是工人,做题我并不擅长,只能得到 D");
    }
}
public static void main(String[] args) {
    Person person = new Student("小明", 18, "男");
    person.exam();

    person = new Worker("小强", 18, "男");
    person.exam();
}

注意,我们如果不希望子类重写某个方法,我们可以在方法前添加final关键字,表示这个方法已经是最终形态:

或者,如果父类中方法的可见性为private,那么子类同样无法访问,也就不能重写,但是可以定义同名方法:

抽象类:

public abstract class Person {   //通过添加abstract关键字,表示这个类是一个抽象类


         String name;   //大体内容其实普通类差不多
         int age;
         String sex;
         String profession;

        Person(String name, int age, String sex, String profession) {
            this.name = name;
            this.age = age;
            this.sex = sex;
            this.profession = profession;
        }
        public abstract void exam();   //抽象类中可以具有抽象方法,也就是说这个方法只有定义,没有方法体
}
public class Worker extends Person{

    public Worker(String name, int age, String sex) {
        super(name, age, sex, "工人");
    }

    @Override
    public void exam() {   //子类必须要实现抽象类所有的抽象方法,这是强制要求的,否则会无法通过编译
        System.out.println("我是工人,做题我并不擅长,只能得到 D");
    }
}
public abstract class Student extends Person{   //如果抽象类的子类也是抽象类,那么可以不用实现父类中的抽象方法
    public Student(String name, int age, String sex) {
        super(name, age, sex, "学生");
    }

    @Override   //抽象类中并不是只能有抽象方法,抽象类中也可以有正常方法的实现
    public void exam() {
        System.out.println("我是学生,我就是小镇做题家,拿个 A 轻轻松松");
    }
}

要实现这样的操作,我们可以将人类变成抽象类,抽象类比类还要抽象:

而具体的实现,需要由子类来完成,而且如果是子类,必须要实现抽象类中所有抽象方法:

抽象类由于不是具体的类定义(它是类的抽象)可能会存在某些方法没有实现,因此无法直接通过new关键字来直接创建对象:

要使用抽象类,我们只能去创建它的子类对象。抽象类一般只用作继承使用,当然,抽象类的子类也可以是一个抽象类:

注意,抽象方法的访问权限不能为private:因为抽象方法一定要由子类实现,如果子类都访问不了,那么还有什么意义呢?所以说不能为私有。

接口:

接口甚至比抽象类还抽象,他只代表某个确切的功能!也就是只包含方法的定义,甚至都不是一个类!接口一般只代表某些功能的抽象,接口包含了一些列方法的定义,类可以实现这个接口,表示类支持接口代表的功能(类似于一个插件,只能作为一个附属功能加在主体上,同时具体实现还需要由主体来实现)

public interface Study {    //使用interface表示这是一个接口
    void study();    //接口中只能定义访问权限为public抽象方法,其中public和abstract关键字可以省略
}
public class Student extends Person implements Study {   //使用implements关键字来实现接口
    public Student(String name, int age, String sex) {
        super(name, age, sex, "学生");
    }

    @Override
    public void study() {    //实现接口时,同样需要将接口中所有的抽象方法全部实现
        System.out.println("我会学习!");
    }
}
public class Teacher extends Person implements Study {
    protected Teacher(String name, int age, String sex) {
        super(name, age, sex, "教师");
    }

    @Override
    public void study() {
        System.out.println("我会加倍学习!");
    }
}
public class Student extends Person implements Study, A, B, C {  //多个接口的实现使用逗号隔开
  
}
public interface Study {
    public static final int a = 10;   //接口中定义的静态变量只能是public static final的
  
  public static void test(){    //接口中定义的静态方法也只能是public的
        System.out.println("我是静态方法");
    }
    
    void study();
}
public static void main(String[] args) {
    System.out.println(Study.a);
    Study.test();
}

接口不同于继承,接口可以同时实现多个:

我们可以让类实现这个接口:用implements关键词

所以说有些人说接口其实就是Java中的多继承,但是我个人认为这种说法是错的,实际上实现接口更像是一个类的功能列表,作为附加功能存在,一个类可以附加很多个功能,接口的使用和继承的概念有一定的出入,顶多说是多继承的一种替代方案。

接口跟抽象类一样,不能直接创建对象,但是我们也可以将接口实现类的对象以接口的形式去使用:

接口不同于类,接口中不允许存在成员变量和成员方法,但是可以存在静态变量和静态方法,在接口中定义的变量只能是:

枚举类:

public class Student extends Person implements Study {

    private String status;   //状态,可以是跑步、学习、睡觉这三个之中的其中一种

    public String getStatus() {
        return status;
    }

    public void setStatus(String status) {
        this.status = status;
    }
}
public enum Status {   //enum表示这是一个枚举类,枚举类的语法稍微有一些不一样
    RUNNING, STUDY, SLEEP;    //直接写每个状态的名字即可,最后面分号可以不打,但是推荐打上
}
public enum Status {
    RUNNING("睡觉"), STUDY("学习"), SLEEP("睡觉");   //无参构造方法被覆盖,创建枚举需要添加参数(本质就是调用的构造方法)

    private final String name;    //枚举的成员变量
    Status(String name){    //覆盖原有构造方法(默认private,只能内部使用!)
        this.name = name;
    }

    public String getName() {   //获取封装的成员变量
        return name;
    }
}
public static void main(String[] args) {
    Student student = new Student("小明", 18, "男");
    student.setStatus(Status.RUNNING);
    System.out.println(student.getStatus().getName());
}

既然枚举类型是普通的类,那么我们也可以给枚举类型添加独有的成员方法

学习资源来自(147条消息) JavaSE笔记(三)重制版_青空の霞光的博客-CSDN博客

(再次学习时自己做的笔记)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值