【Java】面向对象(上):介绍及组成

Java基础复习之面向对象

面向对象 vs 面向过程

  • 面向过程,强调的是功能行为,以函数为最小单位,考虑怎么做。
  • 面向对象,将功能封装进对象,强调具备了功能的对象,以类/对象为最小单位,考虑谁来做。

面向对象的思想概述

类(Class)对象(Object)是面向对象的核心概念。

  • 类是对一类事物的描述,是抽象的、概念上的定义
  • 对象是实际存在的该类事物的每个个体,因而也称为实例(instance)

可以理解为:类 = 抽象概念的人;对象 = 实实在在的某个人

理解万事万物皆对象

在Java语言范畴中,我们都将功能、方法等封装到类中,通过类的实例化,来调用具体的功能结构

涉及到Java语言与前端Html、后端的数据库交互时,前后端的结构在Java层面交互时,都体现为类、对象。

面向对象程序设计的重点是类的设计 ,而类的设计,其实就是类的成员的设计

面向对象的简单使用

Java类及类的成员

常见的类的成员有:

  • 属 性:对应类中的成员变量
  • 行 为:对应类中的成员方法
  • Field = 属性 = 成员变量
  • Method = (成员)方法 = 函数
  • 创建类的对象 = 类的实例化 = 实例化类

比较完整的例子

创建Java自定义类

步骤:

  1. 定义类(考虑修饰符、类名)

  2. 编写类的属性(考虑修饰符、属性类型、属性名、初始化值)

  3. 编写类的方法(考虑修饰符、返回值类型、方法名、形参等)

public class Animal {
	public int legs;
	public void eat(){
		System.out.println(“Eating.”);
	}
	public viod move(){
    System.out.println(“Move.”);
    }
}

类的访问机制

  • 在一个类中的访问机制:类中的方法可以直接访问类中的成员变量。
    • (例外:static方法访问非static,编译不通过。)
  • 在不同类中的访问机制:先创建要访问类的对象,再用对象访问类中定义的成员
 public class Zoo{
    public static void main(String args[]){
    //创建对象
    Animal xb = new Animal();
    xb.legs=4;//访问属性
    System.out.println(xb.legs);
    xb.eat();//访问方法
    xb.move();//访问方法
    }

内存解析

Person p1 = new Person();
Person p2 = new Person();
Person p3 = p1;//没有创建新对象,共用一个堆空间中的对象实体,共同指向的堆空间地址。

如果创建了一个类的多个对象,则每个对象都独立的拥有一套类的属性。(非static的)
意味着:如果我们修改一个对象的属性a,则不会影响另外一个对象属性a的值。
若两个对象指向同一个堆空间,则修改的是一个对象的属性

匿名对象

我们也可以不定义对象的句柄,而直接调用这个对象的方法。这 样的对象叫做匿名对象。

如:new Person().shout();

使用场景:如果对一个对象只需要进行一次方法调用,那么就可以使用匿名对象。

我们经常将匿名对象作为实参传递给一个方法调用。

对象的成员

属性(成员变量)

成员变量 vs 属性变量

  • 相同点

    • 格式: 数据类型 变量名 = 变量值;
    • 先声明,后使用
    • 变量都有其作用域
  • 不同点

    • 在类中声明的位置不同

      • 属性:直接定义在类的一对{}
      • 局部变量:方法形参位置、方法内部、代码块内、构造器形参位置、构造器内部
    • 权限修饰符不同

      • 属性:在声明属性时使用权限修饰符指明其权限
        • 常用的权限修饰符:private、public、缺省(不用加修饰符)、protected
      • 局部变量:不可以使用权限修饰符
    • 默认初始化值的情况

      • 属性:类的属性,根据其数据类型,都有默认初始化值。

        • //整型
          byte、short、int、long:0
          //浮点型
          float、double:0.0
          //字符型
          char:'\u0000'
          //布尔型
          boolean:false
          //引用数据类型
          类、数组、接口:null
          
      • 局部变量:没默认初始化值,所以未赋值的局部变量不能调用

    • 内存加载位置

      • 属性:堆空间或静态域内
      • 局部变量:栈空间

方法

什么是方法(method、函数):

  • 方法是类或对象行为特征的抽象,用来完成某个功能操作。在某些语言中 也称为函数或过程。
  • 将功能封装为方法的目的是,可以实现代码重用,简化代码
  • Java里的方法不能独立存在,所有的方法必须定义在类里

方法的声明格式

修饰符 返回值类型 方法名(参数类型 形参1, 参数类型 形参2, ….){
	方法体程序代码
	return 返回值; 
}
  • 修饰符:public,缺省,private, protected等

  • 返回值:方法在执行完毕后返还给调用它的程序的数据。

  • 返回值类型:

    • 没有返回值:void。
    • 有返回值,声明出返回值的类型。与方法体中“return 返回值”搭配使用
  • 方法名:属于标识符,命名时遵循标识符命名规则和规范,见名知意

  • 形参列表:可以包含零个,一个或多个参数。多个参数时,中间用,隔开

方法的分类

按照是否有形参及返回值

方法的调用

方法通过方法名被调用,且只有被调用才会执行。

  • 方法被调用一次,就会执行一次
  • 没有具体返回值的情况,返回值类型用关键字void表示,那么方法体中可 以不必使用return语句。如果使用,仅用来表示结束方法
  • 定义方法时,方法的结果应该返回给调用者,交由调用者处理。
  • 方法中只能调用方法或属性,不可以在方法内部定义方法。

方法的重载

定义

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

两同一不同:同一个类、相同方法名;参数列表不同(参数个数不同,参数类型不同)

注意:返回值类型不影响是否重载

举例

//如下的4个方法构成了重载
public void getSum(int i,int j){
	System.out.println("1");
}

public void getSum(double d1,double d2){
	System.out.println("2");
}

public void getSum(String s ,int i){  
	System.out.println("3");
}

public void getSum(int i,String s){
	System.out.println("4");
}

类型相同的形参顺序不同也算重载

不构成重载的举例:

//如下的3个方法不能与上述4个方法构成重载
public int getSum(int i,int j){
	return 0;
}

public void getSum(int m,int n){

}

private void getSum(int i,int j){
	
}

如何判断是否构成方法的重载?

严格按照定义判断:两同一不同。

跟方法的权限修饰符、返回值类型、形参变量名、方法体都没关系!

面试题

方法的重载与重写的区别?

可变个数形参的方法

JavaSE 5.0 中提供了Varargs(variable number of arguments)机制,允许直接定

义能和多个实参相匹配的形参。从而,可以用一种更简单的方式,来传递个数可

变的实参。

//JDK 5.0以前:采用数组形参来定义方法,传入多个同一类型变量 
public static void test(int a ,String[] books); 

//JDK5.0:采用可变个数形参来定义方法,传入多个同一类型变量 
public static void test(int a ,String ... books);

注意:

  • 可变个数形参的格式:数据类型 ... 变量名
  • 当调用可变个数形参的方法时,传入的参数个数可以是:0个,1个,2个,。。
  • 可变个数形参的方法与本类中的同名但形参不同的方法之间构成重载
  • 可变个数形参的方法与本类中同名且形参类型也相同的数组之间不构成重载。换句话说二者功能完全相同,不能共存。
  • 可变个数形参在方法的形参中,必须声明在末尾
  • 可变个数形参在方法的形参中,最多只能声明一个可变形参。
public void test(String ...args){	//等同于public void test(String[] args)
    for (int i = 0; i < args.length; i++) {	
        System.out.println(args[i]);
    }
}

@Test
public void main(){
    test("hello","world");
}

方法参数的值传递机制 (重要)

方法必须由其所在类或对象调用才有意义。方法中含有参数类型:

  • 形参:方法声明时的参数
  • 实参:方法调用时实际传给形参的参数值

Java的实参值如何传入方法呢?

Java里方法的参数传递方式只有一种:值传递。 即将实际参数值的副本 传入方法内,而参数本身不受影响

值传递规则:

  • 如果变量是基本数据类型,传递的是变量所保存的数据值
  • 若果是引用数据类型,此时赋值的是变量所保存的数据的地址(含变量的类型)

典型例题与内存解析

public class ValuePass {
    public static void main(String[] args) {
        int m = 10;
        int n = 20;
        ValuePass pass = new ValuePass();
        pass.swap(m,n);
        System.out.println("m="+m+" n="+n);		//m=10 n=20
    }

    public void swap(int m, int n) {
        int temp = m;
        m = n;
        n = temp;
    }
}

main()中的m、n为实参,调用swap()传递的是实参的副本,swap()交换的是自己栈空间的参数,每个方法都有自己的栈空间存放参数,所以实参本身没有调换

换种写法就可以实现调换功能

public class ValuePass {
    public static void main(String[] args) {
        Data data = new Data();
        data.m = 10;
        data.n = 20;
        ValuePass pass = new ValuePass();
        pass.swap(data);
        System.out.println("m="+data.m+" n="+data.n);	//m=20 n=10
    }

    public void swap(Data data) {
        int temp = data.m;
        data.m = data.n;
        data.n = temp;
    }

     static class Data{
        int m;
        int n;
    }
}

此时m、n成功调换,因为参数是引用数据类型,虽然实参和形参仍是两个不同的参数,但指向同一堆空间

构造器

作用:

  • 创建对象(只要是创造对象都要用构造器)
  • 初始化对象的信息

构造器的特征:

  • 它具有与类相同的名称
  • 它不声明返回值类型。(与声明为void不同)
  • 不能被static、final、synchronized、abstract、native修饰,不能有 return语句返回值

格式:

权限修饰符  类名(形参列表){
    
}

注意:

  • 一个类中,至少会有一个构造器,若有多个构造器,则构成重载。

  • 如果没显式的定义类的构造器的话,则系统默认提供一个空参的构造器

  • 一旦我们显式的定义了类的构造器之后,系统就不再提供默认的空参构造器

  • 构造器的权限和类的权限是一样的

  • 构造器可以重载不能重写

属性的赋值顺序

截止到目前,我们讲到了很多位置都可以对类的属性赋值。现总结这几个位置,并指明赋值的先后顺序。

哪些地方可以赋值

① 默认初始化

② 显式初始化

③ 构造器中初始化

④ 通过对象.属性对象.方法的方式赋值

赋值顺序:① - ② - ③ - ④

this指针

可以调用的结构:属性、方法、构造器

this理解为:当前对象 或 当前正在创建的对象

​ 在类的方法中,我们可以使用this.属性this.方法的方式,调用当前对象属性或方法。但是,通常情况下,我们都选择省略。

​ 特殊情况下,如果构造器的形参或方法的形参和类的属性同名时,我们显式的使用this.变量的方式来增强可读性,表明此变量是属性,而非形参。

​ 如果和类的属性同名时,我们显式的使用"this.变量"的方式,表明此变量是属性,而非形参。但是,通常情况下,我们都选择省略

注意:

  • 在类的构造器中可以显式的使用this(形参列表)方式,调用本类中重载的其他构造器
  • 构造器中不能通过this(形参列表)方式调用自己
  • 如果一个类中有n个构造器,则最多有 n - 1构造器中使用了this(形参列表),再多一次就会形成环,造成死循环
  • 规定:this(形参列表)必须声明在当前构造器的首行
  • 构造器内部,最多只能调用一次其他重载的构造器
posted @ 2021-03-25 20:27  至安  阅读(298)  评论(0)    收藏  举报