Java核心-面向对象(上)

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

一、对象/类

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:这次的内容真的有点多,希望能帮助到大家,能看到这里你就是最棒的!

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,997评论 6 502
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,603评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,359评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,309评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,346评论 6 390
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,258评论 1 300
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,122评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,970评论 0 275
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,403评论 1 313
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,596评论 3 334
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,769评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,464评论 5 344
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,075评论 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,705评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,848评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,831评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,678评论 2 354

推荐阅读更多精彩内容