Java编程 面向对象详讲

2022-07-26,,

面向对象上篇*

## 1.类与对象

1.1看一个养猫猫问题

1.2 java语言是面向对象的
计算机语言的发展向接近人的思维方式演变(能编写功能更多软件):
汇编语言 [面向机器] 有助记符 load return …
c语言 [面向过程] 函数=> 完成功能
java语言 [面向对象] 类与对象 => 编写更加复杂,大型软件

		汇编语言(汇编 不会编,不会编汇编)=> 驱动程序

1.3类与对象的关系示意图

1.4 快速入门-面向对象的方式解决养猫问题

import java.util.Scanner;
public class OOPTest
{
	public static void main(String[] args) {
		// int num1 = 20;
		Cat cat1 = new Cat();
		cat1.name = "小白";
		cat1.age = 3;
		cat1.color = "白色";
		System.out.println("猫的信息:" + cat1.name + " " + cat1.age + " " + cat1.color);	
	}
}
//定义一个猫类(数据类型)
class Cat //Cat.class
{
	//属性
	String name; // null
	int age;//0
	String color;//null

	//行为 =》 方法
}
class Car
{
	//属性,成员变量,字段
	String  name;
	double price;
	String color;
}

1.5类和对象的区别和联系
通过上面的案例和讲解我们可以看出:

1)类是抽象的,概念的,代表一类事物,比如人类,猫类…, 即它是数据类型.
2)对象是具体的,实际的,代表一个具体事物, 即 是实例.
3)类是对象的模板,对象是类的一个个体,对应一个实例

1.6对象在内存中存在的形式

1.7属性/成员变量
基本介绍

1)从概念或叫法上看: 成员变量 = 属性 = field (即 成员变量是用来表示属性的,授课中,统一叫 属性)
案例演示:Car(name,price,color)

2)属性是类的一个组成部分,一般是基本数据类型,也可是引用类型(对象,数组)。比如我们前面定义猫类 的 int age 就是属性

属性的注意事项和细节

import java.util.Scanner;
public class ProDetail
{
	public static void main(String[] args) {
		
			int num = 100;
		
			/*
			属性如果不赋值,有默认值,规则和数组一致。
			案例演示:[Cat, Dog] //int 	0,short 0, byte 0, long 0, float 0.0,double 0.0,char \u0000,
			boolean false,String null , 即只有是引用类型,统统为null
			*/
			Cat myCat = new Cat();
			System.out.println("默认值 " + myCat.name + " " + myCat.age + " " + myCat.color);

			Cat myCat2 = new Cat();
			myCat2.name = "小白"; 
			System.out.println("mycat " + myCat.name + " " + myCat.age + " " + myCat.color);
			System.out.println("mycat2 " + myCat2.name + " " + myCat2.age + " " + myCat2.color);
	}
}

//定义一个猫类(数据类型)
class Cat
{
	//属性
	String name;
	int age;
	String color;
	//行为 =》 方法
}

1.8类和对象的内存分配机制(重要)

1.9Java内存的结构分析
1)栈: 一般存放基本数据类型(局部变量)
2)堆: 存放对象(Cat cat , 数组等)
3)方法区:常量池(常量,比如字符串), 类加载信息
4)示意图 [Cat (name, age, price)]

1.10java创建对象的流程简单分析

1)先加载Person 类 , 只会加载一次
2)在堆中,分配空间[地址],并进行默认初始化,比如 name=null age = 0
3)把堆中地址,返回给 p1
4)进行指定初始化 name = “jack” age = 10
5)开始使用p1

1.11类和对象的内存分配机制-练习题

2成员方法

2.1基本介绍

在某些情况下,我们要需要定义成员方法。比如人类:除了有一些属性外( 年龄,姓名…),我们人类还有一些行为比如:可以说话、跑步…,通过学习,我们人类还可以做算术题。这时就要用成员方法才能完成。现在要求对Cat类完善。

2.2成员方法快速入门

1)添加speak 成员方法,输出 我是一只好猫
2)添加jisuan 成员方法,可以计算从 1+…+1000的结果
3)添加cal 成员方法,该方法可以接收一个数n,计算从 1+…+n 的结果
4)添加getSum成员方法,可以计算两个数的和
5)代码:

import java.util.Scanner;

//成员方法的使用
public class MethodTest
{
	public static void main(String[] args) {
		//调用方法
		//1. 创建对象
		Cat myCat = new Cat();
		//2. 调用方法
		myCat.speak();
		myCat.jisuan();
		System.out.println("请输入一个整数");
		Scanner myScanner = new Scanner(System.in);
		int num = myScanner.nextInt();
		myCat.cal(num); // 20 称为 实际参数(实参)
		myCat.getSum(30, 100);
	}
}

//定义一个猫类(数据类型)
class Cat //Cat.class
{
	//属性
	String name; // null
	int age;//0
	String color;//null

	//行为 =》 方法
	//添加speak 成员方法,输出 我是一只好猫
	//解读
	//1. public 表示公开方法
	//2. void 没有返回值
	//3. speak 方法名, () 没有形参
	//4 { } 称为方法体
	//5. 写入你的代码
	public void speak() {
		System.out.println("我是一只好猫");
	}

	//添加jisuan 成员方法,可以计算从 1+..+1000的结果
	public void jisuan() {
		int sum = 0;
		for( int i = 1; i <= 1000; i++) {
			sum += i;
		}
		System.out.println("sum=" + sum);
	}
	//传递参数
	//添加cal 成员方法,该方法可以接收一个数n,计算从 1+..+n 的结果
	//传递参数
	//术语 :int n 称为 形式参数(形参)
	public void cal(int n) {
		int sum = 0;
		for( int i = 1; i <= n; i++) {
			sum += i;
		}
		System.out.println("sum=" + sum);
	}
	//添加getSum成员方法,可以计算两个数的和
	public void getSum(int n1, int n2) {
		int sum = n1 + n2;
		System.out.println("和=" + sum);
	}
}

2.3方法的调用机制原理:(重要!!!)
提示:画出程序执行过程[cal]+说明

2.4为什么需要成员方法
看一个需求:
请遍历一个数组 , 输出数组的各个元素值。
解决思路1,传统的方法,就是使用单个for循环,将数组输出,大家看看问题是什么?

解决思路2: 定义一个类 MyTools ,然后写一个成员方法,看看效果又如何。

代码如下

import java.util.Scanner;

//成员方法的使用
public class WhyMethod
{
	public static void main(String[] args) {
		int[] arr1 = {1, 2, 50, 900, 900, -12};
		//创建MyTools对象
		MyTools tools = new MyTools();
		tools.printArr(arr1);
		int[] arr2 = {1, 2, 50, 900, 900, -12, 10000};
		tools.printArr(arr2);
		int[] arr3 = {1, 2, 50, 900, 900};
		tools.printArr(arr3);
	}
}
class  MyTools //工具类
{
	public void printArr(int[] arr) { //方法
		
		System.out.println();
		for( int i = 0; i < arr.length; i++) {
			System.out.print(arr[i] + ", ");
		}
	}
}

2.5成员方法的好处

1)提高代码的复用性
2)可以将实现的细节封装起来,然后供其他用户来调用即可。!!!

2.6成员方法的定义

2.7注意事项和使用细节
修饰符 (作用是控制 方法使用的范围)
可选,如果不写就是默认的 [public > protected > 默认 > private], 具体在后面说
返回类型
1)一个方法至多有一个返回值 [思考,如何返回多个结果, 数组]
2)返回类型可以为任意类型,包含基本类型或引用类型(数组,对象)
3)如果方法有返回值,则方法体中最后的执行语句必须为return语句,而且要求返回类型必须和return的值类型一致或兼容
4)如果方法没有返回值,则方法体中可以没有return语句,返回类型要求写void
方法名
遵循驼峰命名法,最好见名知义,表达出该功能的意思即可, 比如 得到两个数的和 getSum, 开发中按照规范
参数列表

  1. 一个方法可以有0个参数,也可以有多个参数,中间用逗号隔开(类型 名,类型 名) 【getMax , 比如得到三个数的最大值 】

  2. 参数类型可以为任意类型,包含基本类型或引用类型 【test100】

  3. 调用带参数的方法时,一定对应着参数列表传入相同类型或兼容类型 的参数!【test200】
    4)方法定义时的参数称为形式参数,简称形参;方法调用时的参数称为实际参数,简称实参,实参和形参的类型(兼容)、个数、顺序必须一致!
    方法体
    里面写完成功能的具体的语句,可以为输入、输出、变量、运算、分支、循环、方法调用,但里面不能再定义方法!即:方法不能嵌套定义。[test400]
    成员方法的调用说明

  4. 同一个类中的方法调用:直接调用即可。比如 print(参数);
    案例演示:A类 sayOk 调用 print()

  5. 跨类中的方法A类调用B类方法:需要通过对象名调用。比如 对象名.方法名(参数); 案例演示:B类 sayHello 调用 print()
    代码

import java.util.Scanner;
public class MethodDetail
{
	public static void main(String[] args) {
		
		//一个方法至多有一个返回值  [思考,如何返回多个结果, 数组.]

		//创建对象
		Cat myCat = new Cat();
		//解读
		//1. myCat.m1(4) 返回一个int 结果
		int res = myCat.m1(5);
		System.out.println("res=" + res);

		//2. 测试数组
		// myCat.m2(1, 4) 返回一个数组
		int[] reses = myCat.m2(1, 4);
		System.out.println("和=" + reses[0]);
		System.out.println("差=" + reses[1]);


		//public void m6(int n1, double d1, int[] arr) 
		int[] arr = {};
		myCat.m6(10, 1, arr);

		//测试
		A aObj = new A();
		aObj.sayOk();
	}
}

class B
{
	public void sayHello() {
		//需要通过对象名调用
		A aObj = new A();
		aObj.sayHi();
	}
}

class A
{
	//同一个类中的方法调用:直接调用即可
	public void sayHi() {
		System.out.println("say hi");
	}
	public void sayOk() {
		sayHi();
		System.out.println("say ok");
	}
}
class Cat
{
	//一个方法至多有一个返回值  [思考,如何返回多个结果, 数组.]
	public int m1(int n) {
		return 2 * n;
	}
	public int[] m2(int n1, int n2) {	
		//创建一个数组
		int[] res = new int[2];
		res[0] = n1 + n2;
		res[1] = n1 - n2;
		return res;
	}
	//如果方法有返回值,则方法体中最后的执行语句必须为return语句,
	//而且要求返回类型必须和return的值类型一致或兼容

	public int m3() {
		return (int)1.1;
	}
	//如果方法没有返回值,则方法体中可以没有return语句,返回类型要求写void
	public void m4() { 
	
	}
	//参数类型可以为任意类型,包含基本类型或引用类型
	public void m5(int n, int[] arr) {
		
	}

	//调用带参数的方法时,一定对应着参数列表传入相同类型或兼容类型 的参数!
	public void m6(int n1, double d1, int[] arr) {
		//方法体.
		//调用其他方法...
	}	
	//方法不能嵌套定义
	public void m7() {
		
//		public void m8() {
//			
//		}
	}
}

3 成员方法传参机制

3.1基本数据类型的传参机制
看一个案例
编写一个方法,交换两个整数的值。

import java.util.Scanner;

//基本数据类型传递
public class MethodPassPara01
{
	public static void main(String[] args) {
		
		T2 t2 = new T2();
		int a = 30;
		int b = 50;
		t2.swap(a, b);
		System.out.printf("a=%d b=%d\n", a, b);
	}
}

class T2
{
	public void swap( int num1, int num2) {
		
		System.out.println("swap方法中...");
		System.out.printf("num1=%d num2=%d\n", num1, num2);
		int temp = 0;
		temp = num1;
		num1 = num2;
		num2 = temp;
		System.out.printf("num1=%d num2=%d\n", num1, num2);
	}
}
  • 结论及示意图 基本数据类型,传递的是值(元素内容, 值拷贝), 形参的任何改变不影响实参!
  • 示意图

3.2引用数据类型的传参机制

  • 看一个案例
    B类中编写一个方法test100,可以接收一个数组,在方法中修改该数组,看看原来的数组是否变化?
    B类中编写一个方法test200,可以接收一个Person(age,sal)对象,在方法中修改该对象属性,看看原来的对象是否变化?
import java.util.Scanner;
//基本数据类型传递
public class MethodPassPara02
{
	public static void main(String[] args) {
		int[] arr = {1,2,3};
		T3 t3 = new T3();
		t3.test100(arr);
		//看看 arr 的情况
		for( int i = 0; i < arr.length; i++) {
			System.out.print(arr[i] + "\t");
		}
	}
}
class T3
{
	public void test100(int[] arr ) {
		
		arr[0] = 100;
	}
}

结论及示意图

引用类型传递的是值(地址),可以通过形参影响实参

  • 再看一个案例,下面的方法会对原来的对象有影响吗?
    p=null 和 p = new Person(); 对应示意图
import java.util.Scanner;

//基本数据类型传递
public class MethodPassParaExer01
{
	public static void main(String[] args) {
		
		Person p = new Person();
		p.name = "tom";
		p.age = 12;
		T5 t5 = new T5();
		//t5.m1(p);
		//t5.m2(p);
		t5.m3(p);
		System.out.println(p.name + " " + p.age);// tom, 12
	}
}

class Person
{
	String name;
	int age;
}

class T5
{
	public void m3(Person p) {
		p = new Person();
		p.age = 500;
	}

	public void m1(Person p) {
		p.age = 100;
	}

	public void m2(Person p) {
		p = null;
	}
}

3.3成员方法返回类型是引用类型应用实例
先练习
1)编写类MyTools类,编写一个方法可以打印二维数组的数据。
2)编写一个方法copyArray,可以复制一个数组,返回复制的数组。
扩展:可以接收一个参数,指定拷贝原数组的多少个元素。
比如:{1,2, 0, 78, 999}
3)编写一个方法copyPerson,可以复制一个Person对象,返回复制的对象。克隆对象。。, 注意得到新对象和原来的对象是两个独立的对象,只是他们的属性相同
代码

import java.util.Scanner;

//基本数据类型传递
public class MethodPassParaExer02
{
	public static void main(String[] args) {
		int[] arr = {1, 2, 3, 4, 5};
		MyTools mt = new MyTools();
		int[] arrNew = mt.copyArray(arr, -1);

		for( int i = 0; i < arrNew.length; i++) {
			System.out.print(arrNew[i] + "\t");
		}
	}
}
class Person
{
	String name;
	int age;
}

//编写类MyTools类,编写一个方法可以打印二维数组的数据
class MyTools
{
	public void printArr(int[][] arr) {
		for( int i = 0; i <  arr.length; i++) {
			for( int j = 0; j < arr[i].length; j++) {
				System.out.print(arr[i][j] + "\t");
			}
			System.out.println();
		}
	}

	//编写一个方法copyArray,可以复制一个数组,返回复制的数组
	//扩展:可以接收一个参数,指定拷贝原数组的多少个元素
	public  int[] copyArray(int[] arr, int size) {
		//求出实际应该拷贝几个元素
		//程序员 你想如何处理....
		int len = size > arr.length || size <=0  ? arr.length : size; 
		
		
//		int[] arrNew = new int[arr.length];
		int[] arrNew = new int[len];

		for( int i = 0; i < len; i++) {
			arrNew[i] = arr[i];
		}
		return arrNew;
	}

	//拷贝一个Person 
	public Person copyPerson(Person p) {
		//创建一个新人
		Person newPerson = new Person();
		newPerson.name = p.name;
		newPerson.age = p.age;

		return newPerson;
	}
}

补充:public 类也可以写方法,并在 main 创建对象,调用方法

import java.util.Scanner;

//基本数据类型传递
public class ObjectUse //类
{
	public static void main(String[] args) {

		//使用
		ObjectUse ou = new ObjectUse();
		ou.sayHi();
		
	}

	//方法
	public void sayHi() {
		System.out.println("say hi");
	}

	public void sayOk() {
		sayHi();
	}
}

4方法的重载(OverLoad)

4.1基本介绍
java中允许同一个类中,多个同名方法的存在,但要求 形参列表不一致!
比如:System.out.println(); out是PrintStream类型

4.2重载的好处
1)减轻了起名的麻烦
2)减轻了记名的麻烦

4.3重载的快速入门案例
看一个案例
【要求:类名MyPrint,方法名为print,可以打印 等边三角形,矩形,立方体。示意】

public class OverLoadTest
{
	public static void main(String[] args) {
		
		MyPrint mp = new MyPrint();
		mp.print(10);
		mp.print(1, 2, 3);
		
	}

}

//要求:类名MyPrint,方法名为print,可以打印 等边三角形,矩形,立方体。示意
class MyPrint {

	public void print(int len) {
		System.out.println("打印 等边三角形 边长=" + len);
	}

	

	public void print(int len, int width) {
		System.out.println("打印 矩形 长=" + len + " 宽=" + width);
	}

	public void print(int len, int width, int height) {
		System.out.println("打印 立方体 长=" + len + " 宽=" + width + " 高=" + height);
	}
	
}

4.4注意事项和使用细节

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

案例:类:MyCalculator 方法:calculate
calculate(int n1, int n2)
calculate(int n1, double n2)
calculate(double n2, int n1)
calculate(int n1, int n2,int n3)

5 可变参数

5.1基本概念

jdk5.0出现的新特性,java提供了一种机制,可以允许将同一个类中多个同名同功能但参数个数不同的方法,封装成一个方法。

5.2基本语法
访问修饰符 返回类型 方法名(数据类型… 形参名){
}

5.3快速入门案例(VarArgusDemo.java)
看一个案例 类 MethodUtils,方法 sum 【可以计算 2个数的和,3个数的和 , 4. 5, 。。】
utils 工具集
代码

//演示可变参数使用
public class VarArgs
{
	public static void main(String[] args) {
		VarArgs va = new VarArgs();
		double res1 = va.sum(1, 2, 3, 9, 1.1);
		System.out.println("res1=" + res1);
		double[] arr = {1,2,4};
		double res2 = va.sum(arr);
	}

	//演示可变参数使用
	//说明
	//1. double... 后面的三个小点,是规定
	//2. 这时 args 称为 可变形参
	//3. args 可变形参的本质就是数组
	//4. 实参可以传递数组,但是需要通过 数组名
	//5. 不能在定义 sum(double[] arr), 会认为重复定义
	public  double sum(double... args) {
		
		double totalSum = 0.0;
		for( int i = 0;  i < args.length; i++) {
			totalSum += args[i];
		}

		return totalSum;
	}
}

5.4注意事项和细节

1)可变参数的实参可以为0个或任意多个。
2)可变参数的实参可以为数组。
3)可变参数的本质就是数组.
4)可变参数可以和普通类型的参数一起放在形参列表,但必须保证可变参数在最后
5)一个形参列表中只能出现一个可变参数
6)代码

//演示可变参数使用
public class VarArgsDetail
{
	public static void main(String[] args) {
		
		VarArgs va = new VarArgs();
		
		//细节1: 可变参数的实参可以为0个或任意多个
		va.sum();

		//可变参数的实参可以为数组
		double[] arr = {1,2,4};
		double res2 = va.sum(arr);
	}

	//可变参数可以和普通类型的参数一起放在形参列表,但必须保证可变参数在最后
	public void m1(String name, String... args) {
		
	}
	//一个形参列表中只能出现一个可变参数
//	public void m2(int... args1 , String... args2) {
//		
//	}
	//演示可变参数使用
	//说明
	//1. double... 后面的三个小点,是规定
	//2. 这时 args 称为 可变形参
	//3. args 可变形参的本质就是数组
	//4. 实参可以传递数组,但是需要通过 数组名
	//5. 不能在定义 sum(double[] arr), 会认为重复定义
	public  double sum(double... args) {
		double totalSum = 0.0;
		for( int i = 0;  i < args.length; i++) {
			totalSum += args[i];
		}
		return totalSum;
	}
}

6创建Java自定义类步骤总结(OOP(oriented[面向] object[对象] programming[编程]))

**
6.1步骤

1)定义类,确定类名
2)编写类的属性
3)编写类的方法
4)创建对象,使用方法。

    ~~**自己先练习,后面有代码示例 具体问本人 本人QQ:825794519
    还有韩顺平老师的java原视频**~~  

import java.util.Scanner;
public class BoxExer
{
	public static void main(String[] args) {
	
		Scanner myScanner = new Scanner(System.in);
		Box box = new Box();
		System.out.println("长");
		box.len = myScanner.nextDouble();
		System.out.println("宽");
		box.width = myScanner.nextDouble();
		System.out.println("高");
		box.height = myScanner.nextDouble();

		System.out.println("体积=" + box.volume());
		
	}
}

/*
编程创建一个Box类,在其中定义三个属性表示一个立方体的长、宽和高,长宽高可以通过控制台输入。
定义一个方法获取立方体的体积(volume)。
创建一个对象,打印给定尺寸的立方体的体积
*/

class Box
{
	double len;
	double width;
	double height;

	public double volume() {
		return len * width * height;
	}
}

6.2景区门票案例

1)一个景区根据游人的年龄收取不同价格的门票。
2)请编写游人类,根据年龄段决定能够购买的门票价格并输出
3)规则:年龄>18 , 门票为20元,其它情况免费。
4)可以循环从控制台输入名字和年龄,打印门票收费情况, 如果名字输入 n ,则退出程序。
5)代码

import java.util.Scanner;

//游客
public class VisitorExer 
{
	public static void main(String[] args) {
	
		Scanner myScanner = new Scanner(System.in);
		//得到年龄
		do
		{
			//创建一个游客
			Visitor v = new Visitor();
			System.out.println("姓名:");
			v.name = myScanner.next();
			if( "n".equals(v.name)) {
				break;
			}
			System.out.println("年龄:");
			v.age = myScanner.nextInt();
			//计算
			v.ticketMoney();
			//显示
			v.showInfo();
		}while (true);		
	}
}

/*
1.一个景区根据游人的年龄收取不同价格的门票。
2.请编写游人类,根据年龄段决定能够购买的门票价格并输出
3.规则:年龄>18 , 门票为20元,其它情况免费。
4.可以循环从控制台输入名字和年龄,打印门票收费情况, 如果名字输入 n ,则退出程序。

*/

class Visitor
{
	String name; //名字
	int age; //年龄
	double payMoney;//应付
	//写一个方法,得到应付
	public void ticketMoney() {
		//规则:年龄>18 , 门票为20元,其它情况免费
		if(age > 18) {
			payMoney = 20;
		} 
	}
	//显示方法
	public void showInfo() {
		
		if(payMoney != 0) {
			System.out.println(name+ " 年龄是" + age + " 应付票价" + payMoney);
		} else {
			System.out.println(name+ " 年龄是" + age + " 免费");
		}
	}

}

7属性和局部变量作用域

7.1基本使用

1)面向对象中,变量作用域是非常重要知识点,相对来说不是特别好理解,请大家注意听,认真思考,要求深刻掌握变量作用域。

2)在java编程中,主要的变量就是属性(成员变量)和局部变量。A类:sum

3)我们说的局部变量一般是指在成员方法中定义的变量。【举例】

4)java中作用域的分类
全局变量:也就是属性,作用域为整个类体 A类:sum sub 等方法使用属性 【举例】
局部变量:也就是除了属性之外的其他变量,作用域为定义它的代码块中!

5)全局变量可以不赋值,直接使用,因为有默认值,局部变量必须赋值后,才能使用,因为没有默认值。[举例]

7.2注意事项和细节使用

1)属性全局变量和局部变量可以重名,访问时遵循就近原则。

2)在同一个作用域中,比如在同一个成员方法中,两个局部变量,不能重名。[举例]

3)全局变量,存储在堆中。局部变量,存储在栈中,需要画一个示意图说明。【重要】

4)全局变量,生命周期较长,伴随着对象的创建而创建,伴随着对象的死亡而死亡。局部变量,生命周期较短,伴随着它的代码块的执行而创建,伴随着代码块的结束而死亡。即在一次方法调用过程中。【每调用一次方法,就开一个方法栈,这个是由操作系统决定的】

5)作用域不同
全局变量:可以被本类使用,或其他类使用(通过对象调用)
局部变量:只能在本类中对应的方法中的作用域内使用

6)修饰符不同
全局变量/属性可以加修饰符
局部变量不可以加修饰符

7)特别说明: 如果我们在方法中,是new 对象,比如 Person p = new Person();
p在方法中, 对象数据空间在堆中…, 如果p 没有返回,则方法结束后,对象成为垃圾,被回收,如果返回给 其它方法,比如main , 则可以继续使用

import java.util.Scanner;

//游客
public class VarScopeTest 
{
	public static void main(String[] args) {
	}
}

class A {
	int num = 10;//属性
	int age;  //默认0

	public void m1() {
		int total = 30; //局部变量
		System.out.println(num);
	}
	public void m2() {
		//不能使用total
		System.out.println(num);
	}
	public void m3() {
		//全局变量可以不赋值,直接使用,因为有默认值,局部变量必须赋值后,才能使用,因为没有默认值
		System.out.println(age);
		int personNum = 9; //局部变量
		System.out.println(personNum);
	}
}

8构造方法

8.1看一个需求

我们来看一个需求:前面我们在创建人类的对象时,是先把一个对象创建好后,再给他的年龄和姓名属性赋值,如果现在我要求,在创建人类的对象时,就直接指定这个对象的年龄和姓名,该怎么做? 这时就可以使用构造方法/构造器。

8.2基本语法

[修饰符] 方法名(参数列表){
构造方法体
}

说明:
1)构造器的修饰符可以默认
2)构造器没有返回值
3)方法名 和类名字必须一样
4)参数列表 和 成员方法一样的规则
5)构造器的调用有系统JVM 来调用

8.3基本介绍

构造方法又叫构造器(constructor),是类的一种特殊的方法,它的主要作用是完成对新对象的初始化。它有几个特点:
1)方法名和类名相同
2)没有返回值
3)在创建一个类的新对象时,系统会自动的调用该类的构造方法完成对新对象的初始化。

8.4快速入门

现在我们就用构造方法来完成刚才提出的问题:在创建人类的对象时,就直接指定这个对象的年龄和姓名,该怎么做?
代码

import java.util.Scanner;

//游客
public class ConTest 
{
	public static void main(String[] args) {
		
		//传统写法
//		Person p1 = new Person();
//		p1.name = "jack";
//		p1.age = 20;

		//构造器
		Person p2 = new Person("tom", 30);
		System.out.println(p2.name + " " + p2.age);
	}
}

class Person
{
	String name;
	int age;

	//构造器
	public  Person(String pName, int pAge) {
		System.out.println("构造器被调用....");
		name = pName;
		age = pAge;
	}
}

8.5注意事项和使用细节
1)一个类可以定义多个不同的构造方法,构造方法重载
比如:我们可以再给Person类定义一个构造方法,用该方法来创建新对象的时候,只指定人名,不需要指定年龄。

2)构造方法名和类名相同

3)构造方法没有返回值

4)主要作用是完成对新对象的初始化, 并不是创建对象

5)在创建新对象时,系统自动的调用该类的构造方法

6)如果程序员没有定义构造方法,系统会自动给类生成一个默认无参构造方法(也叫默认构造方法),比如 Person (){}

7)一旦定义了自己的构造方法,默认的构造方法就覆盖了,就不能再使用默认的无参构造方法,除非显示的定义一下,即: Person(){};

8)代码

import java.util.Scanner;

//游客
public class ConDetail
{
	public static void main(String[] args) {

		new Dog("旺财");
		new Person();		
	}

}

//如果程序员没有定义构造方法,系统会自动给类生成一个默认无参构造方法(也叫默认构造方法),
//比如 Person (){}
class Person {

	//默认的一个无参构造器

	//一旦定义了自己的构造方法,默认的构造方法就覆盖了,
	//就不能再使用默认的无参构造方法,除非显示的定义一下
	public Person(String name) {
		
	}

	public Person() {}
}

class Dog {
	//一个类可以定义多个不同的构造方法,构造方法重载
	String name;
	int age;

	//第1个构造器
	public  Dog(String dName) {
		System.out.println("ok~~");
		name = dName;
		
	}

	//第2个构造器
	public Dog(String dName, int dAge) {
		name = dName;
		age = dAge;
	}

	
}

8.6对象创建的流程分析
看一个案例
class Person{
int age=90;
String name;
Person(String n,int a){
name=n;
age=a;
}}
Person p=new Person(“小倩”,20);

流程分析(面试题)
1)加载 Person 类 (Person.class), 只会加载一次
2)在堆中 开数据空间 , 得到一个地址
3)数据的初始化
(1) 默认初始化 age = 0, name = null
(2) 显示初始化 age = 90 , name = null
(3) 构造器初始化 age= 20 name = “小倩”
(4) 把 堆中的地址,返回给 p
(5) 使用

9this关键字

9.1看一段代码,引出this

9.2什么是this
java虚拟机会给每个对象分配 this,代表当前对象。坦白的讲,要明白this 不是件容易的事,我给大家打一个比方。[上帝创世界小故事]

9.3深入理解this
为了进一步理解this,我们再看一个案例 (ThisTest.java)

public class ThisTest {

	public static void main(String[] args) {
		
		Dog dog = new Dog("旺财", 5);
		System.out.println("dog的地址(hashcode=)" + dog.hashCode());
		dog.showInfo(); 

		Dog dog2 = new Dog("来福", 2);
		System.out.println("dog2的地址(hashcode=)" + dog2.hashCode());
		dog.showInfo(); 
		//哪个对象调用,this就代表哪个对象
		dog.m1();
		dog2.m1();

	}
}

class Dog{

	public String name; // null
	public int age; //0

	//我们形参,本质就是 局部变量
	public Dog(String name, int  age){
		System.out.println(this.hashCode());
		this.name = name;
		this.age = age;
	}
	public void m1() {
		System.out.println(this.name);
		System.out.println("m1 this.hashCode=" + this.hashCode());
	}
	public void showInfo(){
		System.out.println(name + "\t" + age + "\t");
	}
}

对应的this理解的示意图

9.4this的注意事项和使用细节
1)this关键字可以用来访问本类的属性、方法、构造器
2)this用于区分当前类的成员和局部变量
3)访问成员方法的语法:this.方法名(参数列表);
4)访问构造方法(构造器)语法:this(参数列表);
5)this不能在类定义的外部使用,只能在类定义的方法中使用
6)代码

public class ThisDetail {

	public static void main(String[] args) {
		
		
		AA a = new AA();
		a.m2();

		System.out.println(a.name); // smith

		AA a2 = new AA("king");
		System.out.println(a2.name); // king

		
	}
}

class AA {

	int age = 10;
	String name = "tom";

	public AA() { //构造器1
		//访问构造方法(构造器)语法:this(参数列表)
		this("smith"); // this 可以调用其它构造器, 需要在构造器内
	}

	public AA(String name) {
		//this用于区分当前类的成员和局部变量
		this.name = name;
	}

	public void m1() {
		//this关键字可以用来访问本类的属性、方法、构造器
		System.out.println(this.age);
	}

	public void hi() {
		System.out.println("hi");
	}
	public void m2() {
		System.out.println("m2()");
		//访问成员方法的语法:this.方法名(参数列表);
		this.hi(); // 可以访问 本类的 hi();
	}
}

本文地址:https://blog.csdn.net/huluo1/article/details/110449876

《Java编程 面向对象详讲.doc》

下载本文的Word格式文档,以方便收藏与打印。