Java面向对象基础

面向对象的概念

面向对象OOP是一种编程范式,主要是将类型的特征和方法抽离出来,放到一个类型,统一管理,减少代码的重复类,提供可复用性和可维护性。

创建一个类并实例化

使用class创建一个类, name等叫做属性 或 成员变量 或字段
使用new创建一个对象,可以使用.来获取对象的属性或方法

public class QuickStart {
    public static void main(String[] args) {
        // 创建实例
        Cat cat1 = new Cat();
        cat1.name = "小黄";
        cat1.age = 8;
        cat1.weight = 2.3;
        cat1.color = "#fdfdfd";
        System.out.println("名字" + cat1.name + " 年龄" + cat1.age 
        + " 体重" + cat1.weight + " 颜色" + cat1.color);

    }
}

class Cat{

    String name;
    int age;
    double weight;
    String color;
}

属性的默认值

类的属性是有默认值的,所以即使你不给它赋值也可以使用。
它的默认值和数组的一样: int 0 short 0 byte 0 long 0 float 0.0 double 0.0 char \u0000 boolean false String null

成员方法

即方法,一些定义在类中的函数
使用成员方法可以提高代码的复用性,可以将实现的细节封装起来,然后供其他用户来调用

成员方法的结构

访问修饰符 返回数据的类型 方法名 (形参列表) {
    // 方法体
  语句;
  return 返回值;
}
  1. 形参列表 表示用户输入的参数以及对应的类型
  2. 返回数据的类型 表示成员方法输出 没有返回值时为void
  3. return语句并不是必须的

一般例子

public class Method {
    public static void main(String[] args) {

        Person p = new Person();
        p.name = "lczmx";
        p.age = 100;
        p.speak();

        Person p2 = new Person();
        p2.name = "山本";
        p.say("我日!!", p2);
        System.out.println(p.getAge());

    }

}

class Person {
    String name;
    int age;
    /*
    1. 方法 成员方法
    2. public表示公开
    3. void 表示没有返回值
    4. speak 是方法名 () 表示形参列表
    5. {} 是方法体, 写我们要执行的的代码
    */
    public void speak(){
            System.out.println("我是一个好人");
    }
    // 使用形参
    public void say(String words, Person p) {
        System.out.println(words + " " + p.name);
    }

    // 返回参数, 并访问自身的属性
    public int getAge(){
        return this.age;
    }
}

细节问题

  1. 访问修饰符(作用是控制方法使用的范围)
    如果不写默认访问,(有四种:public,protected,默认private),具体在后面说
  2. 返回数据类型
    一个方法最多有一个返回值 (多个结果可以使用数组返回)
  3. 返回类型可以为任意类型,包含基本类型或引用类型(数组,对象)
    如果方法要求有返回数据类型,则方法体中最后的执行语句必须为return值;而且要求返回值类型必须和return的值类型一致或兼容
    如果方法是void,则方法体中可以没有return语句,或者只写return;
  4. 方法名
    遵循驼峰命名法,最好见名知义,表达出该功能的意思即可
  5. 方法不能嵌套定义

调用机制

  1. 当程序执行到方法时,会开辟一个独立的栈空间
  2. 当方法执行完毕后或return后,就会返回,该方法的栈空间就会被销毁
  3. 返回到调用方法的地方,执行其他代码
  4. 当main方法执行完毕后,整个程序退出

示意图:
示意图

传参注意点

  1. 参数类型可以为任意类型,包含基本类型或引用类型
  2. 调用带参数的方法时,一定对应着参数列表传入相同类型或兼容类型的参数
  3. 方法定义时的参数称为形式参数,简称形参:方法调用时的传入参数称为实际参数,简称实参
  4. 实参和形参的类型要一致或兼容、个数顺序必须一致
  5. 引用类型传递的是地址, 可以通过形参影响实参
  6. 基本数据类型,传递的是值(值拷贝),形参的任何改变不影响实参

方法重载

java中允许同一个类中,多个同名方法的存在,但要求形参列表不一致,这就是方法重载
重载的好处:

  1. 减轻了起名的麻烦
  2. 减轻了记名的麻烦

重载的要求:

  1. 方法名:必须相同
  2. 形参列表:必须不同 (形参类型个数顺序,至少有一样不同,参数名无要求)
  3. 返回类型:无要求

使用例子:

public class OverLoad {
    public static void main(String[] args) {
        MyCalculator calc = new MyCalculator();
        System.out.println(calc.calculate(1, 1));
        System.out.println(calc.calculate(1, 3.3));
        System.out.println(calc.calculate(2.3, 1));
        System.out.println(calc.calculate(1, 1, 10));

    }
}

class MyCalculator {
    public int  calculate(int n1, int n2) {
        return n1 + n2;
    }
    public double calculate(int n1, double n2) {
         return n1 + n2;
    }
    
    public  double calculate(double n1, int n2) {
         return n1 + n2;
    }
    public int calculate(int n1, int n2, int n3) {
        return n1 + n2 + n3;
    }
}

可变参数

java允许将同一个类中多个同名同功能但参数个数不同的方法,封装成一个方法, 就可以通过可变参数实现
即参数个数不确定时(0个或多个),可以使用可变参数接收数据。
基本语法:

访问修饰符 返回类型 方法名 (数据类型... 形参名) {

}

注意:一个形参列表中只能有一个可变参数

使用例子:

public class VarParameter{
    public static void main(String[] args) {
        MyMethod method = new MyMethod();
        System.out.println(method.sum(1,2,10,12));
        System.out.println(method.showScore("lczmx", 1.1,2.123,99.2,12));

    }
}

class MyMethod {
    /**
    1. int... 表示接受可变参数, 类型为int (可以接收0-多个int)
    2. 使用可变参数时,可以当做数组使用

    注意:
    !!! 可变参数可以与普通参数一起使用, 但可变参数必须在后面
                            public int (int num, int... numbers) {}
    !!! 一个形参列表中只能有一个可变参数
                            public int (String... arr1, int... arr2){} 报错!!
    */
    public int sum(int... numbers){
        int res = 0;
        for (int i : numbers) {
            res += i;
        }
        return res;

    }

    // 练习
    public String showScore(String name, double... scoreArr) {
        /**
        有三个方法,分别实现返回姓名和两门课成绩(总分),返回姓名和三门课成绩(总分),
        返回姓名和五门课成绩(总分)。封装成一个可变参数的方法
        */
        double res = 0d;
        for (double i : scoreArr) {
            res += i;
        }
        return name + "的总成绩为: " + res;
    }

}

作用域

  1. 在java编程中,主要的变量就是属性(成员变量)和局部变量
  2. 我们说的局部变量一般是指在 成员方法中定义的变量,作用域为定义它的代码块中
  3. 而全局变量就是属性,可以在整个类中使用,且可以通过对象.xx的形式让外部类访问
  4. 全局变量(属性)可以不赋值,直接使用,因为有默认值,局部变量必须赋值后,才能使用,因为没有默认值
  5. 属性和局部变量可以重名,访问时遵循就近原侧
  6. 在同一个作用域中,比如在同一个成员方法中,两个局部变量,不能重名
  7. 属性生命周期较长,伴随着对象的创建而创建,伴随着对象的销毁而销毁。局部变量,生命周期较短,伴随着它的代码块的执行而创建,伴随着代码块的结束而销毁。
  8. 全局变量/属性可以加修饰符,局部变量不可以加修饰符

构造器

构造方法又叫构造器(constructor),是类的一种特殊的方法,它的主要作用是完成对新对象的初始化。
构造器基本语法:

[修饰符] 方法名 (形参列表) {
    方法体;
}

注意点:

  1. 构造器的修饰符可以是默认
  2. 构造器没有返回值,它只是初始化对象而已
  3. 方法名必须和类名一样
  4. 参数列表规则和方法的一样
  5. 构造器的调用由系统完成
  6. java默认有一个空构造器,类名(){},自定义后会被覆盖 (可以使用javap指令反编译查看)

一般的使用例子:

public class Constructor{
    public static void main(String[] args) {
        // 写了构造器函数 必须根据函数传值, 否则报错
        Person p = new Person("lczmx", 18);
        System.out.println(p.name);

    }
}
class Person {
    String name;
    int age;

    // ======= 一般使用
    // 1. 名称一致
    // 2. 形参形式和方法的一样
    // 3. 没有返回值,不能写void
    public Person(String name, int age){
        this.age = age;
        this.name = name;
    }
}

this关键字

JVM会给每个对象分配this, 表示当前对象

  1. this关键字可以用来访问本类的属性、方法、构造器
  2. this用于区分当前类的属性和局部变量
  3. 访问成员方法的语法:this.方法名(参数列表)
  4. 访问构造器语法:ths(参数列表):注意只能在构造器中使用(即只能在构造器中访问另外一个构造器,必须放在第一条语句)
  5. this不能在类定义的外部使用,只能在类定义的方法中使用

使用例子:

/*
定义Person类,里面有name、age属性,并提供compareTo比较方法,用于判断
是否和另一个人相等,名字和年龄完全一样,就返回true,否则返回false
*/
public class This {
    public static void main(String[] args) {
        Person p1 = new Person("lczmx", 18);
        Person p2 = new Person("lczmx", 20);
        Person p3 = new Person("lczmx", 20);
        System.out.println(p1.compareTo(p2));
        System.out.println(p2.compareTo(p3));

    }
}

class Person{
    int age;
    String name;

    Person(String name, int age) {
        this.age = age;
        this.name = name;
    }
    public boolean compareTo(Person p) {
        return p.age == this.age && p.name.equals(this.name);
    }
}

使用其他构造器

一个类可以定义多个不同的构造器,即构造器重载
在构造器中可以使用this,访问其它构造器,但只能访问一次

使用例子:

public class Demo {
    public static void main (String[] args) {
        Employee e = new Employee("老王", '男', 29, "财务", 3000.8);
         }
}

class Employee {

    String name;
    char gender;
    int age;
    String position;
    double salary;
    // 三个构造器
    public Employee(String name, char gender, int age, String position, double salary){
        this(name, gender, age);
        // !! 只能用一个 不能复用两个
        this.position = position;
        this.salary = salary;
    }
    public Employee(String name, char gender, int age) {
        this.name = name;
        this.gender = gender;
        this.age = age;

    }
    public Employee(String position, double salary) {
        this.position = position;
        this.salary = salary;
    }


}

使用类在内存中的细节

比如有一个类:

class Person {
    int age = 90;
  String name;
  Person (String name, int age) {
      this.name = name;
    this.age = age;
  }
}

Person p = new Person("小王", 22);
  1. 加载类信息(之后加载一次)

  2. 在堆中分配空间(地址)

  3. 完成对象初始化

    • 默认初始化,age = 0 name=null
    • 显示初始化,age= 90
    • 构造器初始化,age = 22 name = “小王”
  4. 将对象在堆中的地址返回给p

附上一张图,表示对象在内存中的形式
变量在内存中的形式

包的本质就是创建不同的俄文件夹、目录来保存文件。以达到三个作用:

  1. 区分相同名字的类
  2. 当类很多时, 可以很好的管理类
  3. 控制访问范围

一个包下包含很多类,java中常用的包有:

  • java.lang.* 基本包,默认引入,无需手动引入
  • java.util.* 系统提供的工具包、工具类
  • java.net.* 网络包,网络开发
  • java.awt.* 做java界面开发GUI

定义方式

使用package定义一个包,需要放在类的最上面(即import在后面),每个类只能定义一个包。
包的命名规则:只能由字母、数字、下划线和.组成。不能是保留字和关键字。
一般的命名规范是:com.公司名.项目名.业务模块名(如:com.sina.crm.user com.sina.crm.user )

package com.xiaoming;

public class Dog {

}

导入

使用import导入包:

import java.util.Scanner;

// 也可以把包的所有类都导入(但不推荐)
import java.util.*;

访问修饰符

java提供四个访问修饰符,用于控制方法和属性(成员变量)的访问权限

  1. private
    用 private 修饰的类成员,只能被该类自身的方法访问和修改,而不能被任何其他类(包括该类的子类)访问和引用
  2. friendly(默认)
    如果一个类没有访问控制符,说明它具有默认的访问控制特性。限定该类只能被同一个包中的类访问和引用,而不能被其他包中的类使用,即使其他包中有该类的子类
  3. protected
    用保护访问控制符 protected 修饰的类成员可以被三种类所访问:该类自身、与它在同一个包中的其他类以及在其他包中的该类的子类
  4. public
    只要包中的其他类在程序中使用 import 语句引入 public 类,就可以访问和引用这个类

使用例子:

package com.lczmx.modifier;

public class A {
    public int n1 = 1;  // 全部
    protected int n2 = 2; // 同类 包 子类
    int n3 = 3; // 同类 包
    private int n4 = 4; // 同类

    public void m1() {
        System.out.println("n1 = " + n1 + "n2 = "
                + n2 + "n3 = " + n3 + "n4=" + n4);
    }

}

继承

继承的概念和好处

继承可以解决代码复用问题, 所有的子类不需要重新定义这些属性和方法,通过extends来声明继承父类。

继承一般用法

基本语法:

class 子类 extends 父类 {

}

super关键字

对比this

  • TODO

构造器问题

  • TODO

寻找属性

  • TODO

继承的内存布局

  • TODO

封装

  • TODO

多态

  • TODO

作者: 忞翛

出处: https://www.lczmx.top/Java/bf218c3f213c/

版权: 本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。

转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。

在线工具