JavaSE基础之面向对象(上)

Posted 梧桐更兼细雨_到黄昏

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JavaSE基础之面向对象(上)相关的知识,希望对你有一定的参考价值。

一、概述

这里的对象泛指现实中一切事物,每种事物都具备自己的属性和行为。面向对象思想就是在计算机程序设计过程中,参照现实中事物,将事物的属性特征、行为特征抽象出来,描述成计算机事件的设计思想。

它区别于面向过程思想(POP),强调的是通过调用对象的行为来实现功能,而不是自己一步一步的去操作实现。

面向对象的语言中,包含了三大基本特征,即封装、继承和多态。

二、类和对象

什么是类

类是一类具有相同特征的事物的抽象描述,是一组相关属性和行为的集合。可以看成是一类事物的模板,使用事物的属性和行为特征来描述该类事物。
属性:就是事物的状态信息。对比到java中可以看定为一类事物具有的参数属性。
行为:就是事物可以做什么。对比到java中可以看定为一类事物可调用的方法。

什么是对象

对象是一类事物的具体化,是类的一个实例,具备该类事物的所有属性和行为
比如猫
属性:姓名、体重、种类
行为:吃、睡、跑

三、类的定义和对象的创建

Java中用class描述事物:

成员变量:对应事物的属性
成员方法:对应事物的行为

类的定义格式

// 类的声明
public class ClassName {
  //成员变量,在类中,方法外
  //成员方法 ,在类中,方法外
}

对象的创建

new 类名()//也称为匿名对象

//给创建的对象命名
//或者说,把创建的对象用一个引用数据类型的变量保存起来
类名 对象名 = new 类名();

而对象中存储的是什么?是对象地址。

class Student{
    
}
public class TestStudent{
    //Java程序的入口
    public static void main(String[] args){
        System.out.println(new Student());//Student@7852e922

        Student stu = new Student();
        System.out.println(stu);//Student@4e25154f
        
        int[] arr = new int[5];
		System.out.println(arr);//[I@70dea4e
    }
}
//Student和TestStudent没有位置要求,谁在上面谁在下面都可以
//但是如果TestStudent类的main中使用了Student类,那么要求编译时,这个Student已经写好了,不写是不行的
//如果两个类都在一个.java源文件中,只能有一个类是public的

可以看出,类对象和数组对象在直接打印对象名时都显示“类型@对象的hashCode值",所以说类和数组都是引用数据类型,引用数据类型的变量中存储的是对象的地址,或者说指向堆中对象的首地址。

四、成员变量

1、成员变量的分类

实例变量:也叫对象属性,属于某个对象的,通过对象来使用
类变量:也叫类变量,属于整个类的,不是属于某个实例

2、实例变量的使用

(1)实例变量在本类的实例方法中,直接使用

class Circle{
    double radius;
    
    public double getArea(){
        return 3.14 * radius * radius;
    }
}

(2)实例变量在其他类的方法中,需要通过“对象名.实例变量"的方式使用,new一个实例对象

public class TestCircle{
	public static void main(String[] args){
		Circle c = new Circle();
		System.out.println("c这个圆的半径是:" + c.radius);
		
		//修改c这个圆的半径
		c.radius = 1.2;
		System.out.println("c这个圆的半径是:" + c.radius);
	}
}

五、成员变量和局部变量的区别

1、作用范围不一样

成员变量:类中直接使用,其他类通过“对象名.实例变量"的方式使用
局部变量:在当前方法中使用

2、初始化值的不同

成员变量:有默认值
局部变量:无默认值,但定义时需实例化

3、在内存中的位置不同

成员变量:堆内存
局部变量:栈内存

4、生命周期不同

成员变量:随着对象的创建或类的加载而存在,随着对象的消失而消失;没有创建对象,就不会在堆内存中分配内存地址
局部变量: 随着方法的调用而存在,随着方法的调用完毕而消失;方法没有被调用,局部变量不会在栈中分配内存,调用一次分配一次

六、成员方法

1、概念

方法也叫函数,是一个独立功能的定义,是一个类中最基本的功能单元。

把一个功能封装为方法的目的是,可以实现代码重用,从而简少代码量。

2、方法的原则

1.必须先声明后使用

2.不调用不执行,调用一次执行一次,调用时,在栈中压入一个方法栈

3、成员方法的分类

实例方法:属于对象的方法,由对象来调用
静态方法:类方法,属于整个类,不是属于某个实例,由类名来调用。

实例方法的定义格式

修饰符 返回值类型 方法名(参数列表:参数类型1 参数名1,参数类型2 参数名, ...... ){
        方法体;
        return 返回值;
}

实例方法的调用:在其他方法中被调用。对象名.方法名(参数);
形参:在定义方法时方法名后面括号中的变量名称称为形式参数(简称形参),即形参出现在方法定义中。
实参:在调用方式时,需要对方法中需要的参数进行输入,即输入实际参数参与所调用方法的执行。

练习:声明圆类

包含实例变量redius为圆的半径
包含实例方法getArea求圆的面积
包含实例方法getPerimeter求圆对象的周长
包含实例方法getInfo获取圆对象的详细信息
	public class Main{
		public static void main(String[] agrs) {
			Circle c = new Circle();
			c.redius = 2.0;
			System.out.println(c.getInfo());
		}
	}
	
	Class Circle{
		pravite double redius;
		
		public double getArea() {
			return 3.14*redius*reduis;
		}
		
		public double getPerimeter() {
			return 3.14*2*redius;
		}
		
		public String getInfo() {
			return "半径:" + radius + ",面积:" + getArea() + ",周长:" + getPerimeter();
		}
	}

七、可变参数

我们在定义一个方法时,如果形参的个数不确定,那么就可以使用可变参数

八、方法重载

方法重载:指在同一个类中,允许存在一个以上的同名方法,只要它们的参数列表不同即可,与修饰符和返回值类型无关。
参数列表:数据类型个数不同,数据类型不同,数据类型顺序不同。
重载方法调用:JVM通过方法的参数列表,调用不同的方法。

我们看一下下段代码:

class Test06_Overload_Problem2{
	public static void main(String[] args){
		Count c = new Count();
		System.out.println(c.sum(1,2));//(int a, int b)
		System.out.println(c.sum(1,2,3));//(int... args)和(int a, int... args)都兼容,就有问题了
	}
}
//Count类编译没问题,但是调用者有问题
class Count{
	public int sum(int a, int b){
		return a+b;
	}
	public int sum(int... args){
		int sum = 0;
		for(int i=0; i<args.length; i++){
			sum += args[i];
		}
		return sum;
	}
	public int sum(int a, int... args){
		int sum = a;
		for(int i=0; i<args.length; i++){
			sum += args[i];
		}
		return sum;
	}	
}

九、方法的参数传递机制

方法的形参是基本数据类型时,形参值的改变不会影响实参;
方法的形参是引用数据类型时,形参地址值的改变不会影响实参,但是形参地址值里面的数据的改变会影响实参,例如,修改数组元素的值,或修改对象的属性值。

机制一、

public class ParameterTransfer {
     public static void main(String[] args) {
        int num = 30;
        System.out.println("调用add方法前num=" + num); // 30
        add(num);
        System.out.println("调用add方法后num=" + num); // 30
     }
  
     public static void add(int param) {
          param = 100;
     }
}      

我们可以从内存模型来进行分析:
当执行了int num = 30;语句后,JVM在栈内存中开辟一块地址为0X111的内存,里面存放的值为30;当执行add(num);后,JVM又在栈内存中开辟一块地址为0X222的内存,先存放的是30,执行完param = 100;后,0X222的值变成100。但无论怎么改变,0X222中的param值与0X111中的num值没有关系,所以怒骂值不会改变。

机制二、

public class ParameterTransfer {
     public static void main(String[] args) {
          String[] array = new String[] {"huixin"};
          System.out.println("调用reset方法前array中的第0个元素的值是:" + array[0]);
          reset(array);
          System.out.println("调用reset方法后array中的第0个元素的值是:" + array[0]);
     }
  
     public static void reset(String[] param) {
          param[0] = "hello, world!";
     }
}

当传递的是引用数据类型时,结果就不一样了。

当程序执行了String[] array = new String[] {"huixin"}后,JVM在栈内存中开辟了一块地址编号为AD9500内存空间,用于存放array[0]的引用地址,里边放的值是堆内存中的一个地址,示例中的值为BE2500,可以理解为有一个指针指向了堆内存中的编号为BE2500的地址。堆内存中编号为BE2500的这个地址中存放的才是array[0]的值:huixin。

当程序进入reset方法后,将array的值,也就是对象的引用BE2500传了进来。这时,程序在栈内存中又开辟了一块编号为AD9600的内存空间,里边放的值是传递过来的值,即AD9600。可以理解为栈内存中的编号为AD9600的内存中有一个指针,也指向了堆内存中编号为BE2500的内存地址。

而在方法reset中修改了param[0]的值为"hello, 改变了world!"时,实际上则是改变了param AD9600指向堆内存中的地址BE2500内的值。而array AD9500同样指向堆内存BE2500,因此会发生改变。

而同样这个问题也可以看作为对象类型的变量。即String 为new出的对象;但当String为直接赋值而不是new时,则可以看作是基本数据类型。然而String类型是不可变,即创建就不可修改。

https://blog.51cto.com/freej/168676

十、对象数组

数组是用来存储一组数据的容器,一组基本数据类型的数据可以用数组装,那么一组对象也可以使用数组来装。当元素是引用数据类型是,我们称为对象数组。

我们首先要创建对象数组,并且确定数组的长度。否则容易出现空指针异常。

我们通过代码来分析:

Class Preson {
	private String name;
	private int age;
	private double length;
}

public class Main{
	public static void main(String[] args) {
		Preson[] preson = new Preson[4];
		
		// 数组不需要初始化,因为数组会自动初始化为null
		for(int i = 0; i < preson.length; i++) {
			preson[i] = new Preson(); // 定义了属性类型为Preson,里面的元素只能存放Preson对象或子类对象
			preson[i].name = "name" + i;
			preson[i].age = i;
			preson[i].length = 100.0 +i;
		}
	}
} 

我们来看一下代码的内存模型

以上是关于JavaSE基础之面向对象(上)的主要内容,如果未能解决你的问题,请参考以下文章

Javase系列之面向对象

JavaSE基础之封装

JavaSE系列Java面向对象之组合多态与接口

JavaSE基础知识—面向对象(5.1类和对象概念创建及内存分配)

Java从入门到天黑|05JavaSE入门之面向对象(上)

Java从入门到天黑|05JavaSE入门之面向对象(上)