Java核心-面向对象(上)

简介: 面向对象是 Java的主要特性之一,是一种重要的编程思想。首先来认识一下什么是类、对象还有方法。

面向对象是 Java的主要特性之一,是一种重要的编程思想。我们都知道面向对象有三大特性(封装、继承和多态),但学习它们之前,首先要做的基本功就是了解什么是类、对象还有方法,以及它们之间的相关操作和分类,内容大概如下。
面向对象(上).png

一、对象/类

1、概念

1.1 对象(object)

Java中一起皆对象。那么什么是对象?简单理解,对象是一个实例(instance),有状态(属性)和行为(方法)。eg:

学生是一个对象,有姓名、性别、年龄、学号、所属班级、成绩等属性。学生可以有吃饭、睡觉、学习等行为,这些即方法。

员工是一个对象,有姓名、性别、年龄、工号、所属部门、绩效等属性。员工可以有吃饭、睡觉、摸鱼等行为,这些即方法。

不只是人,动物(🐖,🐱,🐕...),植物(花、草、树...)都是对象。简言之,世间一切皆对象。

1.2 类(class)

说完对象,再来说类。说到类,很多人可能会想到"物以类聚,人以群分"。类是一个模板,描述了一类对象的行为和状态。很好理解,eg:

人是一个类,具体每一个人如小明、老王就是一个对象。(这里人就是一个抽象的概念,因为可以再细分如男人/女人)

狗是一个类,具体如沙皮狗、哈巴狗就是一个对象,虽然属于不同的品种,但他们都有狗的特征和行为,都是狗。(这里狗就是一个抽象的概念,因为可以再细分)

可以看到,类可以划的比较宽泛,也可以划的细一点,具体还要看实际的业务需求。简言之,对象是类的实例,类是对象的抽象

2、深入

2.1 类的定义

1)语法

[修饰符] class 类名 {
    0-N 成员变量(字段) // 描述类具有的特性,对象的状态
    0-N 构造器
    0-N 方法            // 描述类具有的功能,对象的行为
}

pass:类可看做是一种自定义的数据类型,可以使用类来定义变量。

关于修饰符之前介绍过,定义类 public、protected、abstract和 static用的较多,各有不同的含义和功能。

成员变量(非静态变量 / 实例变量 / 全局变量):实例变量声明在一个类中,但在方法、构造方法和语句块之外(类中方法外)。

至于构造器和方法,接下来会讲到。

2.2 对象创建、访问/修改属性

1)创建对象
创建对象即实例化一个对象。一般通过​new​关键字来创建对象。还可以通过反射和序列化创建,当然,这都是后话了。

类名 对象名 = new 类名();

2)访问/修改
类/对象的访问成员变量或方法如下

通过 对象.属性 直接赋值的方式修改属性

类.类方法
类.类变量
对象名.成员方法
对象名.成员变量

3)eg

public class Person {   // 定义一个 Person 类,有姓名和年龄两个属性
    String name;    // 姓名
    int age;    // 年龄
    public void eat(){
        System.out.println("吃饭");
    }
    public void sleep(){
        System.out.println("睡觉");
    }
}

class PersonTest{   // 测试类
    public static void main(String[] args) {
        Person p=new Person();  // 创建一个对象 p
        p.name="zhangsan";  // 赋值
        p.age=20;
        System.out.println(p.name+" "+p.age);
        p.name="lishi"; // 通过对象.属性直接赋值的方式修改属性
        System.out.println(p.name+" "+p.age);
        p.eat();    // 调用方法
        p.sleep();
    }
}

测试结果

zhangsan 20
lishi 20
吃饭
睡觉

pass:Java中的测试类是用来是用来对已经写好的功能组件进行测试。上面这种通过新建一个带有main方法的类,利用该类来调用需要测试的类,并把需要测试的数据传入进去的测试方法在前期学习是非常常用的,后期开发则采用更加高效便捷的JUnit单元测试

2.3 常用关键字

以下部分可能刚开始不是那么好理解,慢慢就熟悉了。

1)静态 static
static 修饰的成员称为类成员(类变量、类方法、静态初始化块、静态内部类),其随着所在类的加载而加载,先于该类对象存在(当字节码被加载进 JVM 时类成员就存在了,而对象是后面 new 出来的),被该类所有对象所共享,可以直接用类名调用。

注:被 static修饰的成员方法和成员变量称为类成员,其中,被 static修饰的成员变量称为类变量,被 static修饰的成员方法称为类方法。

2)未被 static修饰
相反,未被 static修饰的成员称为与实例成员(实例变量、实例方法、普通初始化块、实例内部类)

注:未被static修饰的成员方法和成员变量称为实例成员,其中,未被static修饰的成员变量叫做实例变量,未被static修饰的成员方法叫做实例方法。

3)其他注意

局部变量(类的方法中、代码块中的变量)不属于任何类或实例,不能使用 static 修饰;不能修饰构造器。

public只能由对象访问(对象.属性|方法),而 static 静态方法可以在不创建类的对象的情况下访问该方法。

static 修饰的成员(属于类)及构造器不能直接访问没有 static 修饰的成员(属于对象)

由于static 强调的是类,this 和 super 强调的是对象,故 static 修饰的方法中不能使用 this 或 super 引用

4)代码示例(重点)
搞清楚如下代码示例(结合注释)就基本上能理解上面的表达意思。至于第 3)点涉及的构造器、this会在接下来讲,这里我们先记住。

public class Person { // 定义一个 Person 类
    String name;
    int age;    // 实例变量(成员变量)
    static String gender;   // 类变量
    public static void eat(){  // 类方法
        System.out.println("吃饭");
    }
    public void sleep(){    // 实例方法(成员方法)
//        static int i;   // 错误,局部变量不能使用 static 修饰
        System.out.println("睡觉");
    }
}

class PersonTest{   // 测试类
    public static void main(String[] args) {
        // static修饰的成员可以直接用类名调用。
        Person.gender="男";
        Person.eat(); // static 静态方法可以在不创建类的对象情况下访问该方法

        Person p=new Person();  // 创建一个对象 p
        p.name="zhangsan";  // public只能由对象访问(对象.属性|方法)
        p.age=20;
        p.sleep();

        // static修饰的成员被该类所有对象所共享,故也能由对象访问(对象.属性|方法)
        p.gender="女";   // 通过对象.属性直接赋值的方式修改属性
        p.eat();
        System.out.println(p.name+" "+Person.gender+" "+p.age);
    }
}

测试结果(建议自己把代码跑一遍,加深理解)

吃饭
睡觉
吃饭
zhangsan 女 20

5)本类 this
this 是 Java 常用的关键字,可用于任何实例方法内指向当前对象。在方法内部,可以使用隐含的变量 this,它始终指向当前实例。并通过 this.field 就可以访问当前实例的字段(即属性)。若无命名冲突,可以省略 this。eg

public class Person { // 定义一个 Person 类
    private String name;
    public String getName() { // 实例方法
        return name; // 相当于this.name
    }
}

若有局部变量和字段重名,则局部变量优先级更高,就必须加上 this。eg

public class Person {
    private String name;
    public void setName(String name) {
        this.name = name; // 前面的this不可少,少了就变成局部变量name
    }
}

2.4 设置和获取对象数据

1)设置:

  • setter()(属性注入)
  • 构造注入直接调用带参数的构造器,创建对象的同时完成对象字段的初始化(推荐)。

2)获取:

  • getter()方法

3)eg:看懂以下示例即可理解该部分内容

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

    public Person() { //无参构造
    }
    public Person(String name, int age) { //带参构造
        this.name = name;
        this.age = age;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
}
class TestPreson{   // 测试类
    public static void main(String[] args) {
        Person p1=new Person();
        // 1、setter(属性注入)初始化
        p1.setName("zhangsan");
        p1.setAge(13);

        // 2、构造注入,调用构造方法的同时完成初始化(推荐)
        Person p2=new Person("lishi",14);

        System.out.println(p1.getName()+" "+p1.getAge()); // zhangsan 13
        System.out.println(p2.getName()+" "+p2.getAge()); // lishi 14
    }
}

二、方法

方法又称函数,是一个代码块,用于执行某些操作,只在运行时调用。

1、按参数和返回值

其实可以不用分这么细,常用的就那几种,其他了解即可。

1.1 无参无返回值

一般方法内为输出打印某个内容。用直接调用即可。

void:无返回值,有返回值(return)不用 void修饰符

public class Person {
    public static void main(String[] args) {
        eat();  // 直接调用
    }
    public static void eat(){   // 无参无返回值
        System.out.println("吃饭");   
    }
}

1.2 带参无返回值

同上,直接调用。

public class Person {
    public static void main(String[] args) {
        getSum(10,20); //直接调用(记得传参)。
    }
    public static void getSum(int a, int b){   //带参无返回值
        System.out.println(a+b);  
    }
}

1.3 无参有返回值

public class Person {
    public static void main(String[] args) {
        String massage=getMassage();   //赋值调用
        System.out.println(massage);

        System.out.println(getMassage()); //输出调用
    }
    public static String getMassage(){ //无参有返回值
        return "Hello!";
    }
}

1.4 带参有返回值(常用)

带参有返回值方法的定义和调用。一般情况最常用赋值调用

public class Person {
    public static void main(String[] args) {
        getSum(10,20,30); // 1.直接调用(运行不输出结果)
        int sum=getSum(10,20,30); // 2.赋值调用
        System.out.println(sum);
        System.out.println(getSum(10,20,30)); // 3.输出调用
    }
    public static int getSum(int num1,int num2,int num3){ // 带参有返回值
        return num1+num2+num3;
    }
}

2、构造方法

构造方法是一种特殊的方法,用于创建对象时执行必要的初始化操作

注:构造方法的名称必须与类名相同,无返回值,且必须通过 new操作符调用构造方法。

2.1 创建实例,初始化实例字段

在创建实例(对象)时,经常需要同时初始化这个实例的字段(属性)。
法1:通过setter()方法,每次需要调用该方法,比较麻烦。

Person p = new Person();
p.setName("老王");
p.setAge(11);
System.out.println(p.getName()+" "+p.getAge());

法2:通过构造方法,在创建实例时就把所有属性都初始化。(推荐)

Person p=new Person("老王",11);
System.out.println(p.getName()+" "+p.getAge());

2.2 默认构造方法(重点)

若未定义构造方法,编译器会自动生成一个默认构造方法(无参构造)。定义了构造方法,编译器不再自动创建默认构造方法
一般而言,最好就是把两个构造方法都定义出来,如下。

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

    public Person() { //默认构造(无参构造)
    }
    public Person(String name, int age) { //带参构造
        this.name = name;
        this.age = age;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
}
class TestPreson{   // 测试类
    public static void main(String[] args) {
        Person p1=new Person("zhangsan",20); //既可调用带参构造方法
        Person p2=new Person(); //也可调用无参构造方法
        System.out.println(p1.getName()+" "+p1.getAge()); // zhangsan 20
        System.out.println(p2.getName()+" "+p2.getAge()); // null 0
    }
}

pass:通过 new 方式调用构造方法

2.3 创建实例初始化顺序

先初始化字段(属性),再初始化构造方法

public class Person {
    private String name = "zhangsan"; // 先字段初始化
    private int age = 20;
    public Person(String name, int age) {
        this.name = name; //再构造方法初始化
        this.age = age;
    }
}

2.4 多构造方法

1)多个构造方法的重载,编译器会根据参数自动判断。如下

public class Person {
    private String name;
    private int age;
    // 创建对象,初始化 name 和 age
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
    public Person(String name) {
        this.name = name;
        this.age = 12;
    }
    // 默认构造器(编译器自动产生)
    public Person() {
    }
}

2)实现构造方法间的相互调用(调用语法:this(, , ...)),以提高代码复用性。如下

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

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
    public Person(String name) {
        this(name, 18); // 调用另一个构造方法Person(String, int)
    }
    public Person() { //无参构造
        this("lishi"); // 调用另一个构造方法Person(String)
    }
    // 提供 getter()和setter()方法,这里只用到getter()
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
}

class TestPreson{   // 测试类
    public static void main(String[] args) {
        Person p=new Person("zhangsan",19); // 调用两个参数的构造方法
        //调用无参构造,层层传递,Person()-->Person(String)-->Person(String, int)
        Person p1=new Person();
        System.out.println(p.getName()+" "+p.getAge());
        System.out.println(p1.getName()+" "+p1.getAge());
    }
}

测试结果

zhangsan 19
lishi 18

分析:(理解了上述代码的可忽略)

第一个输出大家应该都没问题,因为 p调用两个参数的构造方法,并通过构造方法,在创建实例时就把所有属性都初始化,所以输出 zhangsan 19。

来看第二个输出,p1调用的是无参构造方法,但由于Person()无参构造方法又通过 this("lishi")调用了 Person(String name)构造方法,且初始化 name为 lishi,所以 p1.getName()为 lishi,而 Person(String name)构造方法又通过 this(name, 18)调用了 Person(String name, int age)构造方法,且初始化 age为18,所以 p1.getAge()为 18。

2.5 总结

1)实例在创建时通过new操作符会调用其对应的构造方法(用于初始化实例)。
2)没有定义构造方法时,编译器会自动创建一个默认构造方法(无参构造)。
3)显式定义了构造器(构造方法)之后,编译器就不会自动生成默认构造器了,但可以自己手动加上。
4)可定义多个构造方法,编译器会根据参数自动判断。
5)可在一个构造方法内部调用另一个构造方法,便于代码复用。

3、方法重载(重点)

之后在讲到继承时还会有一个重写,要与重载区别开,先打预防针。

3.1 介绍

方法重载(Overload):方法名相同,参数不同

使用重载的目的:功能类似的方法使用同一名字,更容易记住,调用起来更简单(在参数上做修改即可)。

参数不同(体现在)

  • 参数的个数不同
  • 参数的类型不同
  • 参数的个数和类型都不同

    3.2 举例

    1)如 String类提供了多个重载方法 indexOf(),用于查找子串
    int indexOf(int ch):根据字符的Unicode码查找;
    int indexOf(String str):根据字符串查找;
    int indexOf(int ch, int fromIndex):根据字符查找,但指定起始位置;
    int indexOf(String str, int fromIndex)根据字符串查找,但指定起始位置。
    2)再举一个简单例子,如下,实现 hello方法的重载。
    public class Person {
      public static void main(String[] args) {
          String h = hello();
          String h1 = hello("zhangsan");
          String h2 = hello("zhangsan", 16);
          System.out.println(h);
          System.out.println(h1);
          System.out.println(h2);
      }
      public static String hello() {
          return "hello,world";
      }
      public static String hello(String name) {
          return "Hello," + name;
      }
      public static String hello(String name, int age) {
          return "Hello," + name+" "+age;
      }
    }
    
    运行结果
    hello,world
    Hello, zhangsan
    Hello, zhangsan 16
    

    pass:这次的内容真的有点多,希望能帮助到大家,能看到这里你就是最棒的!

相关文章
|
19天前
|
Java
java中面向过程和面向对象区别?
java中面向过程和面向对象区别?
20 1
|
1月前
|
JavaScript 前端开发 Java
还不明白面向对象? 本文带你彻底搞懂面向对象的三大特征(2024年11月Java版)
欢迎来到我的博客,我是瑞雨溪,一名热爱JavaScript和Vue的大一学生。如果你从我的文章中受益,欢迎关注我,我将持续更新更多优质内容。你的支持是我前进的动力!🎉🎉🎉
24 0
还不明白面向对象? 本文带你彻底搞懂面向对象的三大特征(2024年11月Java版)
|
1月前
|
Java 关系型数据库 数据库
面向对象设计原则在Java中的实现与案例分析
【10月更文挑战第25天】本文通过Java语言的具体实现和案例分析,详细介绍了面向对象设计的五大核心原则:单一职责原则、开闭原则、里氏替换原则、接口隔离原则和依赖倒置原则。这些原则帮助开发者构建更加灵活、可维护和可扩展的系统,不仅适用于Java,也适用于其他面向对象编程语言。
37 2
|
3月前
|
Java 编译器
封装,继承,多态【Java面向对象知识回顾①】
本文回顾了Java面向对象编程的三大特性:封装、继承和多态。封装通过将数据和方法结合在类中并隐藏实现细节来保护对象状态,继承允许新类扩展现有类的功能,而多态则允许对象在不同情况下表现出不同的行为,这些特性共同提高了代码的复用性、扩展性和灵活性。
封装,继承,多态【Java面向对象知识回顾①】
|
3月前
|
Java
java中面向过程和面向对象区别?
java中面向过程和面向对象区别?
37 4
|
3月前
|
Java
接口和抽象类【Java面向对象知识回顾②】
本文讨论了Java中抽象类和接口的概念与区别。抽象类是不能被实例化的类,可以包含抽象和非抽象方法,常用作其他类的基类。接口是一种纯抽象类型,只包含抽象方法和常量,不能被实例化,且实现接口的类必须实现接口中定义的所有方法。文章还比较了抽象类和接口在实现方式、方法类型、成员变量、构造方法和访问修饰符等方面的不同,并探讨了它们的使用场景。
接口和抽象类【Java面向对象知识回顾②】
|
2月前
|
存储 Java 程序员
Java基础-面向对象
Java基础-面向对象
20 0
|
4月前
|
Java 数据处理 开发者
【Java基础面试十二】、说一说你对面向对象的理解
这篇文章阐述了面向对象是一种以类和对象为基础,通过封装、继承和多态等概念来模拟现实世界中的事物及其相互关系的程序设计方法,它强调以事物为中心进行思考和系统构造,与结构化程序设计相比,更符合人类的自然思维方式。
【Java基础面试十二】、说一说你对面向对象的理解
|
4月前
|
Java
【Java基础面试十三】、面向对象的三大特征是什么?
这篇文章介绍了面向对象程序设计的三大基本特征:封装、继承和多态,其中封装隐藏对象实现细节,继承实现软件复用,多态允许子类对象表现出不同的行为特征。
【Java基础面试十三】、面向对象的三大特征是什么?
|
3月前
|
安全 Java Go
面向对象程序设计语言:Java
Java语言语法和C语言和C++语言很接近,很容易学习和使用,Java丢弃了C++中很少使用的、很难理解的、令人迷惑的特性,Java语言不使用指针,而是引用,并提供了自动分配和回收内存空间,使得程序员不必为内存管理而担忧
75 2