java面向对象-Java类及类的成员

32 阅读9分钟

Java类及类的成员

介绍

一、Java面向对象学习的三条主线:(第4-6章)

1.Java类及类的成员:属性、方法、构造器;代码块、内部类

2.面向对象的三大特征:封装性、继承性、多态性、(抽象性)

3.其它关键字:this、super、static、final、abstract、interface、package、import等

类的结构

对象的内存解析

属性与局部变量的对比

类中属性的使用
属性(成员变量)   vs  局部变量
1.相同点:
1.1  定义变量的格式:数据类型  变量名 = 变量值
1.2 先声明,后使用
1.3 变量都有其对应的作用域 


2.不同点:
2.1 在类中声明的位置的不同
属性:直接定义在类的一对{}内
局部变量:声明在方法内、方法形参、代码块内、构造器形参、构造器内部的变量

2.2 关于权限修饰符的不同
属性:可以在声明属性时,指明其权限,使用权限修饰符。
常用的权限修饰符:privatepublic、缺省、protected  --->封装性
局部变量:不可以使用权限修饰符。

2.3 默认初始化值的情况:
属性:类的属性,根据其类型,都有默认初始化值。
整型(byteshortintlong):0
浮点型(floatdouble):0.0
字符型(char):0  (或'\u0000')
布尔型(boolean):false

引用数据类型(类、数组、接口):null

局部变量:没有默认初始化值。
意味着,我们在调用局部变量之前,一定要显式赋值。
特别地:形参在调用时,我们赋值即可。

2.4 在内存中加载的位置:
属性:加载到堆空间中   (非static)
		局部变量:加载到栈空间
package com.atguigu.java;
/*
 * 类中属性的使用
 * 
 * 属性(成员变量)   vs  局部变量
 * 1.相同点:
 * 		1.1  定义变量的格式:数据类型  变量名 = 变量值
 * 		1.2 先声明,后使用
 * 		1.3 变量都有其对应的作用域 
 * 
 * 
 * 2.不同点:
 * 		2.1 在类中声明的位置的不同
 * 		属性:直接定义在类的一对{}内
 * 		局部变量:声明在方法内、方法形参、代码块内、构造器形参、构造器内部的变量
 * 		
 * 		2.2 关于权限修饰符的不同
 * 		属性:可以在声明属性时,指明其权限,使用权限修饰符。
 * 			常用的权限修饰符:private、public、缺省、protected  --->封装性
 * 			目前,大家声明属性时,都使用缺省就可以了。
 * 		局部变量:不可以使用权限修饰符。
 * 
 * 		2.3 默认初始化值的情况:
 * 		属性:类的属性,根据其类型,都有默认初始化值。
 * 			整型(byte、short、int、long):0
 * 			浮点型(float、double):0.0
 * 			字符型(char):0  (或'\u0000')
 * 			布尔型(boolean):false
 * 
 * 			引用数据类型(类、数组、接口):null
 * 
 * 		局部变量:没有默认初始化值。
 *  		意味着,我们在调用局部变量之前,一定要显式赋值。
 * 			特别地:形参在调用时,我们赋值即可。
 * 
 * 		2.4 在内存中加载的位置:
 * 		属性:加载到堆空间中   (非static)
 * 		局部变量:加载到栈空间
 * 
 */
public class UserTest {
	
	public static void main(String[] args) {
		User u1 = new User();
		System.out.println(u1.name);
		System.out.println(u1.age);
		System.out.println(u1.isMale);
		
		u1.talk("韩语");
		
		u1.eat();
		
	}
}

class User{
	//属性(或成员变量)
	String name;
	public int age;
	boolean isMale;
	
	
	public void talk(String language){//language:形参,也是局部变量
		System.out.println("我们使用" + language + "进行交流");
		
	}
	
	public void eat(){
		String food = "烙饼";//局部变量
		System.out.println("北方人喜欢吃:" + food);
	}
	
}

成员变量和局部变量的内存位置

方法

方法的重载

/*
 * 方法的重载(overload)  loading...
 * 
 * 1.定义:在同一个类中,允许存在一个以上的同名方法,只要它们的参数个数或者参数类型不同即可。
 * 	
 *  "两同一不同":同一个类、相同方法名
 *            参数列表不同:参数个数不同,参数类型不同,参数顺序不同
 * 
 * 2. 举例:
 *    Arrays类中重载的sort() / binarySearch()
 * 
 * 3.判断是否是重载:
 *    跟方法的权限修饰符、返回值类型、形参变量名、方法体都没有关系!
 *    
 * 4. 在通过对象调用方法时,如何确定某一个指定的方法:
 *      方法名 和 参数列表
 */
public class OverLoadTest {
	public static void main(String[] args) {
		
		OverLoadTest test = new OverLoadTest();
		test.getSum(1,2);
		
		
	}
	
	//如下的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){
//		
//	}
	
	
}
练习

可变个数的形参

如果有确定的方法会选择确定的方法,可变参数方法的优先级最低。


package com.atguigu.java1;
/*
 * 可变个数形参的方法
 * 
 * 1.jdk 5.0新增的内容
 * 2.具体使用:
 *   2.1 可变个数形参的格式:数据类型 ... 变量名
 *   2.2 当调用可变个数形参的方法时,传入的参数个数可以是:0个,1个,2个,。。。
 *   2.3 可变个数形参的方法与本类中方法名相同,形参不同的方法之间构成重载
 *   2.4 可变个数形参的方法与本类中方法名相同,形参类型也相同的数组之间不构成重载。换句话说,二者不能共存。
 *   2.5 可变个数形参在方法的形参中,必须声明在末尾
 * 	 2.6  可变个数形参在方法的形参中,最多只能声明一个可变形参。
 * 
 */
public class MethodArgsTest {
	
	public static void main(String[] args) {
		
		MethodArgsTest test = new MethodArgsTest();
		test.show(12);
//		test.show("hello");
//		test.show("hello","world");
//		test.show();
		
		test.show(new String[]{"AA","BB","CC"});
		
	}
	
	
	public void show(int i){
		
	}
	
	public void show(String s){
		System.out.println("show(String)");
	}
	
	public void show(String ... strs){
		System.out.println("show(String ... strs)");
		
		for(int i = 0;i < strs.length;i++){
			System.out.println(strs[i]);
		}
	}
	//不能与上一个方法同时存在
//	public void show(String[] strs){
//		
//	}
	
	//The variable argument type String of the method 
	//show must be the last parameter
//	public void show(String ...strs,int i){
//		
//	}
	
}
方法参数的值传递机制(极其重要)


值传递案例一

在同一个main方法里面,不涉及到方法传值

package day8;
/*
 * 
 * 关于变量的赋值:
 * 
 *  如果变量是基本数据类型,此时赋值的是变量所保存的数据值。
 *  如果变量是引用数据类型,此时赋值的是变量所保存的数据的地址值。
 * 
 */
public class ValueTransferTest {
	
	public static void main(String[] args) {
		
		System.out.println("***********基本数据类型:****************");
		int m = 10;
		int n = m;
		
		System.out.println("m = " + m + ", n = " + n);
		
		n = 20;
		
		System.out.println("m = " + m + ", n = " + n);
		
		System.out.println("***********引用数据类型:****************");
		
		Order o1 = new Order();
		o1.orderId = 1001;
		
		Order o2 = o1;//赋值以后,o1和o2的地址值相同,都指向了堆空间中同一个对象实体。
		
		System.out.println("o1.orderId = " + o1.orderId + ",o2.orderId = " +o2.orderId);
		
		o2.orderId = 1002;
		
		System.out.println("o1.orderId = " + o1.orderId + ",o2.orderId = " +o2.orderId);
		
	}
	
}

class Order{
	
	int orderId;
	
}


/************基本数据类型:****************
m = 10, n = 10
m = 10, n = 20
***********引用数据类型:****************
o1.orderId = 1001,o2.orderId = 1001
o1.orderId = 1002,o2.orderId = 1002

Process finished with exit code 0*/
值传递案例二
package day8;
/*
 * 方法的形参的传递机制:值传递
 * 
 * 1.形参:方法定义时,声明的小括号内的参数
 *   实参:方法调用时,实际传递给形参的数据
 * 
 * 2.值传递机制:
 * 如果参数是基本数据类型,此时实参赋给形参的是实参真实存储的数据值。
 * 如果参数是引用数据类型,此时实参赋给形参的是实参存储数据的地址值。
 * 
 */
public class ValueTransferTest1 {
	public static void main(String[] args) {
		
		int m = 10;
		int n = 20;
		
		System.out.println("m = " + m + ", n = " + n);
		//交换两个变量的值的操作
//		int temp = m ;
//		m = n;
//		n = temp;
		
		ValueTransferTest1 test = new ValueTransferTest1();
		test.swap(m, n);
		
		System.out.println("m = " + m + ", n = " + n);
		
		
	}
	
	
	public void swap(int m,int n){
		int temp = m ;
		m = n;
		n = temp;
	}
}


/*m = 10, n = 20
m = 10, n = 20
    交换失败,因为java是值传递,这里赋值进来的形参没有进去堆,而是去了栈,当swap方法执行完毕之后什么,temp、m、n全都弹出栈了,所以就会交换失败,输出语句只是输出main方法中的m和n。
*/

值传递案例三
package day8;

public class ValueTransferTest2 {
	
	public static void main(String[] args) {
		
		Data data = new Data();
		
		data.m = 10;
		data.n = 20;
		
		System.out.println("m = " + data.m + ", n = " + data.n);
		
		//交换m和n的值
//		int temp = data.m;
//		data.m = data.n;
//		data.n = temp;
		
		ValueTransferTest2 test = new ValueTransferTest2();
		test.swap(data);
		
		
		System.out.println("m = " + data.m + ", n = " + data.n);
		
	}
	
	public void swap(Data data){
		int temp = data.m;
		data.m = data.n;
		data.n = temp;
	}
	
}

class Data{
	
	int m;
	int n;
	
}


/*
m = 10, n = 20
m = 20, n = 10*/
总结

因为java是值传递,

引用类型要传递地址,交换的时候交换堆中的属性就没问题。

基本数据类型的话,也要注意该值是在栈还是在堆。


练习

注意:画堆栈图,要花详细,最好是把每个方法对应的局部变量也都画出来(用括号括起来,执行完就可以弹出栈,避免干扰),免得漏画,导致漏分析。


网红面试题

第一题

强制退出程序


第二题

第三题

输出

第一个是地址值毫无疑问,但是第二个为什么是输出abc呢,其实就是字符串底层的写法。


复习
1. 什么是方法的重载?
“两同一不同”:同一个类、相同方法名;参数列表不同。
如何调用确定的方法:方法名参数列表

2. 说明Java方法中的参数传递机制的具体体现? 
基本数据类型:数据值
引用数据类型:地址值 (含变量的数据类型)
Person p1 =  new Person();  eat();age
User u1 = p1;//编译错误    (逆向思维、反证法)
u1.eat()  u1.age

3. 成员变量和局部变量在声明的位置上、是否有默认初始化值上、是否能有权限修饰符修饰上、内存分配的位置上有何不同?
见下图。

4. 谈谈return关键字的使用
① 结束方法  ② 针对于有返回值的方法,return + 返回数据

5. 提供如下代码的内存解析
1. 内存结构:栈(局部变量)、堆(new出来的结构:对象(非static成员变量)、数组)
2. 变量:成员变量  vs 局部变量(方法内、方法形参、构造器内、构造器形参、代码块内)

第三题

  1. 成员变量和局部变量在声明的位置上、是否有默认初始化值上、是否能有权限修饰符修饰上、内存分配的位置上有何不同?

输出:hello

原因:如果是传入一个对象,那么修改里面的属性,可能就会修改成功,但是这一个是字符串对象,字符串有一个常量池,而且字符串对象是不可变的,每次修改值都会创建对象,所以s赋值 hi ,只是将 新建一个hi赋值给局部变量,而不是赋值给对象s1。


























JVM内存结构

复习

类与对象

1.面向对象学习的三条主线:

  • 1.Java类及类的成员:属性、方法、构造器;代码块、内部类

  • 2.面向对象的大特征:封装性、继承性、多态性、(抽象性)

  • 3.其它关键字:this、super、static、final、abstract、interface、package、import等

  • “大处着眼,小处着手”

2.面向对象与面向过程(理解)

1.面向过程:强调的是功能行为,以函数为最小单位,考虑怎么做。

2.面向对象:强调具备了功能的对象,以类/对象为最小单位,考虑谁来做。

举例对比:人把大象装进冰箱。

3.完成一个项目(或功能)的思路:

4.面向对象中两个重要的概念:

类:对一类事物的描述,是抽象的、概念上的定义

对象:是实际存在的该类事物的每个个体,因而也称为实例(instance)

面向对象程序设计的重点是类的设计

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

二者的关系:

对象,是由类new出来的,派生出来的。

5.面向对象思想落地实现的规则一

  • 1.创建类,设计类的成员

  • 2.创建类的对象

  • 3.通过“对象.属性”或“对象.方法”调用对象的结构

补充:几个概念的使用说明

  • 属性 = 成员变量 = field = 域、字段

  • 方法 = 成员方法 = 函数 = method

  • 创建类的对象 = 类的实例化 = 实例化类

6.对象的创建与对象的内存解析

典型代码:

Person p1 = new Person();

Person p2 = new Person();

Person p3 = p1;//没有新创建一个对象,共用一个堆空间中的对象实体。

说明:

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

意味着:如果我们修改一个对象的属性a,则不影响另外一个对象属性a的值。

8.理解"万事万物皆对象"

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

  • Scanner,String等

  • 文件:File

  • 网络资源:URL

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

类结构:属性

类的设计中,两个重要结构之一:属性

对比:属性 vs 局部变量

1.相同点:

  • 1.1 定义变量的格式:数据类型 变量名 = 变量值

  • 1.2 先声明,后使用

  • 1.3 变量都其对应的作用域

2.不同点:

2.1 在类中声明的位置的不同

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

  • 局部变量:声明在方法内、方法形参、代码块内、构造器形参、构造器内部的变量

  • 2.2 关于权限修饰符的不同

  • 属性:可以在声明属性时,指明其权限,使用权限修饰符。

  • 常用的权限修饰符:private、public、缺省、protected --->封装性

  • 目前,大家声明属性时,都使用缺省就可以了。

  • 局部变量:不可以使用权限修饰符。

  • 2.3 默认初始化值的情况:

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

  • 整型(byte、short、int、long:0)

  • 浮点型(float、double:0.0)

  • 字符型(char:0 (或'\u0000'))

  • 布尔型(boolean:false)

  • 引用数据类型(类、数组、接口:null)

  • 局部变量:没默认初始化值。

  • 意味着,我们在调用局部变量之前,一定要显式赋值。

  • 特别地:形参在调用时,我们赋值即可。

  • 2.4 在内存中加载的位置:

  • 属性:加载到堆空间中 (非static)

  • 局部变量:加载到栈空间

补充:回顾变量的分类:

方式一:按照数据类型:

方式二:按照在类中声明的位置:

类结构:方法

类的设计中,两个重要结构之二:方法

方法:描述类应该具的功能。

  • 比如:Math类:sqrt()\random() ...

  • Scanner类:nextXxx() ...

  • Arrays类:sort() \ binarySearch() \ toString() \ equals() \ ...

  • 1.举例:

  • public void eat(){}

  • public void sleep(int hour){}

  • public String getName(){}

  • public String getNation(String nation){}

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

  • }

  • 注意:static、final、abstract 来修饰的方法,后面再讲。

    1. 说明:
  • 3.1 关于权限修饰符:默认方法的权限修饰符先都使用public

  • Java规定的4种权限修饰符:private、public、缺省、protected -->封装性再细说

  • 3.2 返回值类型: 返回值 vs 没返回值

  • 3.2.1 如果方法返回值,则必须在方法声明时,指定返回值的类型。同时,方法中,需要使用

  • return关键字来返回指定类型的变量或常量:“return 数据”。

  • 如果方法没返回值,则方法声明时,使用void来表示。通常,没返回值的方法中,就不需要

  • 使用return.但是,如果使用的话,只能“return;”表示结束此方法的意思。

  • 3.2.2 我们定义方法该不该返回值?

  • ① 题目要求

  • ② 凭经验:具体问题具体分析

  • 3.3 方法名:属于标识符,遵循标识符的规则和规范,“见名知意”

  • 3.4 形参列表: 方法可以声明0个,1个,或多个形参。

  • 3.4.1 格式:数据类型1 形参1,数据类型2 形参2,...

  • 3.4.2 我们定义方法时,该不该定义形参?

  • ① 题目要求

  • ② 凭经验:具体问题具体分析

  • 3.5 方法体:方法功能的体现。

  1. 方法的使用中,可以调用当前类的属性或方法
  • 特殊的:方法A中又调用了方法A:递归方法。

  • 方法中,不可以定义方法。