Java基本语法(四)—— 面向对象(上)

183 阅读7分钟

Java基本语法(四)—— 面向对象(上)

类和对象

Class:对一类事物的描述,是抽象的定义。

Object:实际存在该类事物的个体,是实例(instance)。

设计类,就是设计类的成员。

  • 属性(field/域/字段):对应类的成员变量
  • 方法(method):对应类的成员函数

类和对象的使用步骤:

 package com.coderleo.ClassTest;
 /*
  1.创建类、设计类的成员
  2.创建类的对象
  3.通过“对象名.属性名”/“对象名.方法名”调用对象结构
  * */
 ​
 public class PersonTest {
     public static void main(String[] args) {
         //2.实例化对象:类  类名  = new 类();
         Person p1 = new Person();
         
         //3.调用属性:对象名.属性名
         p1.name = "wkm";
         p1.isMale = true;
         System.out.println(p1.age + " " + p1.name + " " + p1.isMale);
         //1 wkm true
         
         //3.调用方法:对象名.方法名
         p1.eat();//人可以吃饭
         p1.sleep();//人可以睡觉
         p1.talk("Chinese");//人可以说话,使用的是:Chinese
         
         
     }
 }
 ​
 ​
 //1.创建类、设计类的成员
 class Person{
     //属性
     String name;
     boolean isMale;
     int age = 1;
     
     //方法
     public void eat(){
         System.out.println("人可以吃饭");
     }
     
     public void sleep(){
         System.out.println("人可以睡觉");
     }
     
     public void talk(String language){
         System.out.println("人可以说话,使用的是:" + language);
     }
 }
 ​

多个对象的关系

创建了一个类的多个对象,则每个对象都独立地拥有一套类的属性(非static)。

接上面的代码:

         Person p2 = new Person();
         System.out.println(p2.name);//null
         
         Person p3;
         p3 = p1;//将p1的地址给了p3,所以p1、p3指向对空间中的同一块地方
         System.out.println(p3.name);//和p1一样,都是“wkm”
         
         p3.age = 10;
         System.out.println(p1.age);//10

对象的内存解析

image-20220922221021251

虚拟机栈:局部变量。

堆:存放new出来的结构(如:数组、对象);对象的属性(非static)加载在堆中。

方法区:类的加载信息、常量池、静态域。

具体例子:

image-20221002174253771

属性(成员变量)和局部变量

属性:直接定义在类的{}内

局部变量:生命在方法内、方法形参、代码块内、构造器形参、构造器内部的变量

方法

声明:权限修饰符 返回值类型 方法名(形参列表){

方法体

}

static、final、abstract等后面讲。

  • 权限修饰符:public、private、protected、缺省(封装时细说)

  • 返回值:

    • 对于有返回值的,需要return相应的类型。
    • 无返回值的(void),可以不用return,或return;表示结束此方法。
  • 方法名:做到见名知意

  • 形参列表:0/多个;形式:类型1 形参1,类型2 形参2......

  • 方法的使用中,可以调用当前类的属性、方法

  • 方法可以递归调用,但不可以在方法内定义新方法。

对象数组的内存解析

image-20221002231805454

stus的每一个元素的默认初始值为null,在使用时要先new,否则就会像第五句一样出现空指针异常

匿名对象

没有显式地赋值给对象一个变量,此类对象即为匿名对象。

由于无变量名,因此只能使用一次。

 package com.leocoder.java;
 ​
 public class AnonymousobjectTest {
 ​
     public static void main(String[] args) {
         // 1.用法:直接new
         new Phone().sendEmail();//发送邮件
         new Phone().playGame();//玩游戏
         
         //2.区别:上述两个new其实不是一个实例,用price属性展现
         new Phone().price = 1000;
         new Phone().showPrice();//0.0,说明和上一个赋值1000的对象不是同一个
         
         //3.开发中的用法
         PhoneMall pm = new PhoneMall();
         pm.phone(new Phone());//在这里直接new一个匿名对象,正常显示发送邮件,玩游戏
     }
 ​
 }
 ​
 class PhoneMall{
     public void phone(Phone phone){
         phone.sendEmail();
         phone.playGame();
     }
 }
 ​
 class Phone{
     double price;
     
     public void sendEmail(){
         System.out.println("发送邮件");
     }
     public void playGame(){
         System.out.println("玩游戏");
     }
     
     public void showPrice(){
         System.out.println(price);
     }
     
 }

方法的其他几个方面

1.方法重载

在一个类中,允许存在一个以上的同名方法,只要它们的参数个数类型不同。

跟方法的权限修饰符、形参名称、方法体的具体内容、返回值是否相同都无关。

一个例子:传入的参数是int,class中只存在double类型的同名方法,就执行此方法:

 public class OverloadTest {
     
     public static void main(String[] args) {
         OverloadTest test = new OverloadTest();
         test.getSum(1,2);//2
         //此时会执行未被注释的double类型getSum方法,因为将1、2参数进行自动类型提升
     }
     
 //  public void getSum(int m, int n){
 //      System.out.println(1);
 //  }
     public void getSum(double m, double n){
         System.out.println(2);
     }
 }

2.可变个数的形参

允许定义能和多个实参匹配的形参。

具体使用:

  • 格式:参数类型 ... 变量名,如:public void show(String ... s)
  • 调用时传入的参数个数可以是0个或多个
  • 方法中可变形参必须在参数列表末尾,因此最多只能声明一个可变形参。

3.值传递机制

  • 如果参数是基本数据类型,此时赋值的是实参所保存的数据值
  • 引用数据类型,此时实参赋给形参的是变量所保存的数据的地址值
 public class ValueTransferTest {
 ​
     public static void main(String[] args) {
         int m = 10;
         int n = 20;
         System.out.println("m: "+m + ", n: " + n);//m: 10, n: 20
 ​
         //形参是基本数据类型,交换不成功
         ValueTransferTest test = new ValueTransferTest();
         test.swap(m, n);
         System.out.println("m: "+m + ", n: " + n);//m: 10, n: 20
         
         //传入引用数据类型,这里是传入一个Data
         Data data = new Data();
         data.m = 40;
         data.n = 50;
         System.out.println("m: "+data.m + ", n: " + data.n);//m: 40, n: 50
         test.swap(data);
         System.out.println("m: "+data.m + ", n: " + data.n);//m: 50, n: 40
     }
     public void swap(int m, int n){
         int temp = m;
         m = n;
         n = temp;
     }
     
     public void swap(Data data){
         int temp = data.m;
         data.m = data.n;
         data.n = temp;
     }
 }
 ​
 class Data{
     int m;
     int n;
 }

4.递归

举例:计算n!

 public class RecursionTest {
     
     public static void main(String[] args) {
         RecursionTest test = new RecursionTest();
         System.out.println(test.factorialValue(8));//40320
     }
     
     public int factorialValue(int n){
         if(n == 0)
             return 1;
         else{
             return n * factorialValue(n-1);
         }
     }
 }

封装与隐蔽

  • 问题引入:由于我们需要对部分属性限制某些条件,只能在方法中添加(setXxx);

同时对于属性需要封装。用法:private 类型 属性名

  • 封装性的体现:

    • 将属性私有化(private)
    • 在类中设置公共方法获取(getXxx)和设置(setXxx)
    • 以上两点在本次使用中体现,封装性的体现还有:不对外暴漏私有方法、单例模式
  • Java规定的四种权限(依次增大):private、缺省、protected、public

    • 四种权限可以修饰:属性、方法、构造器、内部类
    • 修饰class的只能是:public、缺省
修饰符类中同一个包内不同包的子类同一个工程中
privateyes
缺省yesyes
protectedyesyesyes
publicyesyesyesyes

构造器constructor

作用:创建对象;初始化对象的信息

说明:

  • 如果未显示地定义构造器,系统默认提供一个空参的构造器(即我们平时创建对象是:new + 类名() ,new后的即是构造器 );同时这个默认构造器的权限与类的权限一致
  • 构造器定义格式:权限修饰符 类名 (形参列表) {}
  • 构造器也可以重载
  • 一旦定义了构造器,系统不再提供空参构造器

JaveBean

符合以下标准的java类:

  • class是公共的
  • 包含空参的公共constructor
  • 有属性,且提供get、set方法

this关键字

可以修饰属性、方法、构造器

this理解为:当前对象

在类方法中,可以使用"this.属性"/"this.方法",调用当前对象的属性或方法。但通常省略。

  • 不能省略的情况(构造器中同理):方法的形参和属性同名(比如name),想要在方法中(比如setName)设置name的值,必须:this.name = name,其中前一个name是类的属性name,后一个是形参。
  • this调用本类中指定的其他的构造器:*this(形参列表) *。构造器不能调用自己(形成了闭环)。
  • 构造器调用必须在第一行。
  • 构造器内部,最多只能用一个this(形参列表)。

package、import

package:方便对项目中类的管理

  • 使用:在源文件的首行进行声明,使用package声明所属的类或接口
  • 每"."一次,代表一个文件目录
  • 同一个包下,不能定义同名的class

import:

  • 在源文件中显示地导入指定包下的某些类、接口
  • 在package的声明和class的声明之间import
  • 导入多个结构,并列写出即可
  • 可以使用import xxx. *,表示导入XXX包下的所有结构
  • 如果使用的类/接口是lang包下的,可以省略import
  • 如果使用的类/接口是本包下的,不用import
  • 如果在某一源文件中,使用了两个个包下的同名类,至少有一个必须以全类名(package名.class名) 的方式显示
  • import xxx.*表示,导入xxx包下的所有结构,但不包括xxx包下的子包。如需使用某个包下的子包,仍需显示导入
  • import static:导入指定类或接口下的静态结构 (属性、方法)