Java尚硅谷基础笔记-day5面向对象(一)


学习面向对象的三条主线:
1.Java类及类的成员: 属性,方法,构造器,代码块,内部类
2.面向对象的三大特征: 封装性,继承性,多态性,(抽象性)
3.其它关键字:this,super,final

4.1 面向过程与面向对象

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

4.2 Java基本元素:类和对象

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

理解“万事万物皆对象”
1.在Java语言范畴中,我们都将功能,结构等封装到类中,通过类的实例化,来调用具体的功能结构。如:Scanner,String等
文件:file,网络资源:URL;
2.涉及到Java语言与前端Html,后端的数据库交互时,前后端的结构在Java层面交互时,都体现为类,对象。

类的成员:属性和方法
属性=成员变量=field (域 ,字段)
方法=成员方法=函数=method
创建类的对象=类的实例化=实例化类

4.3 对象的创建和使用

类的访问机制
1.在一个类中的访问机制: 类中的方法可以直接访问类中的成员变量。(例外: static方法访问非static, 编译不通过。)
2.在不同类中的访问机制: 先创建要访问类的对象, 再用对象访问类中
定义的成员。

public class classTest1 {
	public static void main(String[] args) {
		Person p1=new Person();
		p1.name = "Tom";
		p1.isMale=true;
		p1.eat();
		p1.sleep();
		Person p3=p1;//将p1地址值赋给p3
		System.out.println(p3.name);//Tom
		p3.age=10;
		System.out.println(p1.name);//10,p3,p1指向同一个对象
	}
}
class Person{
	String name;
	boolean isMale;
	int age=1;
	public void eat(){
		System.out.println(name+"吃饭");
	}
	public void sleep(){
		System.out.println(name+"睡觉");
		eat();//类中访问机制
	}
}

对象的生命周期
在这里插入图片描述
内存解析
运行时候分配空间
JVM内存结构:编译完程序以后,生成一个或多个字节码文件。我们是用JVM中的类的加载器和解释器对生成的字节码文件进行解释运行。
意味着,需要将字节码文件对应的类加载到内存中,涉及到内存解析。
在这里插入图片描述
堆( Heap), 此内存区域的唯一目的就是存放对象实例, 几乎所有的对象实例都在这里分配内存。 这一点在Java虚拟机规范中的描述是:所有的对象实例以及数组都要在堆上分配。

通常所说的栈( Stack),是指虚拟机栈。 虚拟机栈用于存储局部变量等。局部变量表存放了编译期可知长度的各种基本数据类型( boolean、 byte、char 、 short 、 int 、 float 、 long 、double) 、 对象引用( reference类型,它不等同于对象本身, 是对象在堆内存的首地址) 。 方法执行完, 自动释放。

方法区(Method Area),用于存储已被虚拟机加载的类信息、 常量、 静态变量、 即时编译器编译后的代码等数据。
在这里插入图片描述
匿名对象
我们也可以不定义对象的句柄,而直接调用这个对象的方法。这样的对象叫做匿名对象。
如:new Person().sleep;
使用情况:
如果对一个对象只需要进行一次方法调用,那么就可以使用匿名对象。我们经常将匿名对象作为实参传递给一个方法调用。

public class classTest1 {
	public static void main(String[] args) {
		PhoneMall mall=new PhoneMall();
		//Phone p=new Phone();
		//mall.show(p)
		mall.show(new Phone());//将匿名对象传递给方法
	}
}
class PhoneMall{
	public void show(Phone phone){
		phone.sendEmail();
		phone.playGame();
	}
}
class Phone{
	public void sendEmail{
	}
	public void playGame{
	}
}

4.4 类的成员之一:属性

语法格式:修饰符 数据类型 属性名 = 初始化值 ;

属性(成员变量)VS局部变量
在这里插入图片描述
成员变量VS局部变量的内存位置:
在这里插入图片描述

4.5 类的成员之二:方法

方法:描述应该具有的功能
在这里插入图片描述
return关键字的使用
使用范围:使用在方法体中
作用:
1.结束方法
2.针对有返回值类型的方法,使用“return 数据”方法返回所要的数据
方法调用的过程分析
在这里插入图片描述
练习1
在这里插入图片描述

public class classTest1 {
	public static void main(String[] args) {
		Person p1=new Person();
		p1.name = "Tom";
		p1.age=18;
		p1.sex=1;
		p1.study();
		p1.showAge();
		int newAge=p1.addAge(2);//20
		System.out.println(p1.name+"新年龄为:"+newAge);
		System.out.println(p1.age);//20
		Person p2=new Person();
		p2.name="Ali";
		p2.age=23;
		p2.study();
		p2.showAge();	
	}
}
class Person{
	String name;
	int age;
	int sex;
	public void study(){
		System.out.println("studying");
	}
	public void showAge(){
		System.out.println(age);
	}
	public int addAge(int i) {
		age=age+i;
		return age;		
	}
}

内存解析
在这里插入图片描述
练习2
利用面向对象的编程方法,设计类Circle计算圆的面积。

//方式一:
public class classTest1 {
	public static void main(String[] args) {
	Circle c1=new Circle();
	c1.radius=2;
	c1.findArea();	
	}
}
class Circle{
	double radius;
	public void findArea(){
		double area=Math.PI*radius*radius;
		System.out.println("圆的面积为"+area);
	}
}
//方式二:
public class classTest1 {
	public static void main(String[] args) {
	Circle c1=new Circle();
	c1.radius=2;
	//输出方式1
	//double area=c1.findArea();	
	//System.out.println(area);
	//输出方式2
	System.out.println(c1.findArea());//编辑器看到的是返回值
	}
}
class Circle{
	double radius;
	public double findArea(){
		double area=Math.PI*radius*radius;
		return area;
	}
}

练习3
对象数组题目
在这里插入图片描述

public class classTest1 {
	public static void main(String[] args) {
		Student[] stus=new Student[20];
		for(int i=0;i<stus.length;i++) {
			stus[i]=new Student();//对象数组中的每一个都是对象,需要new,类似于二维数组
			stus[i].number=i+1;
			stus[i].state=(int)(Math.random()*(6-1+1)+1);
			stus[i].score=(int)(Math.random()*(100-0+1));
		}
		for(int i=0;i<stus.length;i++) {
			System.out.println(stus[i].number+"\t"+stus[i].state+"\t"+stus[i].score);

		}
		System.out.println("**************");
		//输出state=3学生信息
		for(int i=0;i<stus.length;i++) {
			if(stus[i].state==3) {
				System.out.println(stus[i].number+"\t"+stus[i].state+"\t"+stus[i].score);
			}
		}
		System.out.println("**************");
		//冒泡排序
		for(int i=0;i<stus.length;i++) {
			for(int j=0;j<stus.length-i-1;j++) {
				if(stus[j].score>stus[j+1].score) {
				/*错误:按成绩来排学生的整体排序,不是交互成绩
					int temp=stus[j].score;
					stus[j].score=stus[j+1].score;
					stus[j+1].score=temp;
					*/
					Student temp=stus[j];
					stus[j]=stus[j+1];
					stus[j+1]=temp;
				}
			}
		}
		for(int i=0;i<stus.length;i++) {
			System.out.println(stus[i].number+"\t"+stus[i].state+"\t"+stus[i].score);
		}			
	}
}
class Student{
	int number;
	int state;
	int score;
}

优化:将遍历和查找,排序封装到方法中

public class classTest1 {
	public static void main(String[] args) {
		Student[] stus=new Student[20];
		for(int i=0;i<stus.length;i++) {
			stus[i]=new Student();//
			stus[i].number=i+1;
			stus[i].state=(int)(Math.random()*(6-1+1)+1);
			stus[i].score=(int)(Math.random()*(100-0+1));
		}
		Test test=new Test();
		test.print(stus);
		System.out.println("**************");
		/*方式一查找的使用
		int index=test.getindex(stus,3);
		System.out.println(stus[index].info());
		*/
		test.getindex(stus, 3);
		System.out.println("**************");
		test.sort(stus);		
	}
}
class Student{
	int number;
	int state;
	int score;
	public String info() {
		return number+"\t"+state+"\t"+score;
	}
}
class Test{
	/**
	 * 
	* @Description输出对象数组
	* @author Croc Hou
	* @date 2020-6-2917:58:17
	* @param arr 对象数组
	 */
	public void print(Student[] arr) {
		for(int i=0;i<arr.length;i++) {			
			System.out.println(arr[i].info());
		}
	}
	/**
	 * 
	* @Description 找到对应年级的学生
	* @author Croc Hou
	* @date 2020-6-2917:58:47
	* @param arr
	* @param state
	 */
	/*
	//方式1getindex
	public int getindex(Student[] arr,int state) {
		int index=-1;
		for(int i=0;i<arr.length;i++) {
			if(arr[i].state==state) {
				index=i;
			}
		}
		return index;
	}
	*/
	//方式2getindex
	public void getindex(Student[] arr,int state) {
		for(int i=0;i<arr.length;i++) {
			if(arr[i].state==state) {
				System.out.println(arr[i].info());
			}
		}
	}
/**
 * 
* @Description 冒泡排序
* @author Croc Hou
* @date 2020-6-2917:59:09
* @param arr
 */
	public void sort(Student[] arr) {
		for(int i=0;i<arr.length;i++) {
			for(int j=0;j<arr.length-i-1;j++) {
				if(arr[j].score>arr[j+1].score) {
					Student temp=arr[j];
					arr[j]=arr[j+1];
					arr[j+1]=temp;
				}
			}
		}
		print(arr);		
	}
}

内存解析
在这里插入图片描述
引用类型的变量,只可能存储两类值:null或地址值(含变量类型)

方法重载
1.定义:在同一个类中,允许一个以上的同名方法,只要它们的参数个数或者参数类型不同即可
2.例如:Arrays类中重载的sort(),binarySearch()
3.判断是否是重载:跟方法的权限修饰符,返回值类型,形参变量名,方法体都没有关系。
4.在通过对象调用方法时,如何确定某一个指定的方法:方法名–参数列表。

//以下构成方法重载
	public void getsum(String s,int i) {
		
	}
	public void getsum(int i,String s) {
		
	}

练习1
在这里插入图片描述
可变个数的形参
jdk 5.0新增的内容
具体使用:
1.可变个数形参的格式:数据类型…变量名
2.当调用可变个数形参的方法时,传入的参数个数可以使:0,1,2…
3.可变个数形参的方法与本类中方法名相同,形参不同的方法构成重载
4.可变个数形参的方法与本类中方法名相同,形参类型也相同的数组之间不构成重载.两者不能同时存在。String … strs与String[] strs
5.可变个数形参在方法的形参中,必须声明在末尾
6.可变个数形参在方法的形参中,最多只能声明一个可变形参
应用场景:数据库得多个查找条件

public class classTest2 {
	public static void main(String[] args) {
		MethodargsTest test=new MethodargsTest();
		test.show("hello");//show(String)
		test.show("hello","world");//show(String ... strs)
		test.show();//show(String ... strs)
		test.show(new String[] {"AA","BB","CC"});//show(String ... strs)		
	}
}
class MethodargsTest{
	public void show(String s) {
		System.out.println("show(String)");
	}
	public void show(String ... strs) {
		System.out.println("show(String ... strs)");
	}
	/*与前面String ... strs等价,jdk5.0之前
	public void show(String[] strs) {
		System.out.println("show(String)");
	}
	*/
}

方法参数的值传递
变量的赋值:
基本数据类型:赋值的是变量所保存的数据值;
引用数据类型:变量所保存的数据的地址值。

//基本数据类型
//从内存结构来考虑,m和n都在栈内,n改变不影响m
int m=10;
int n=m;
System.out.println("m="+m+",n="+n);//m=10,n=10
n=20;
System.out.println("m="+m+",n="+n);//m=10,n=20
//引用数据类型
//从内存结构来考虑,o1和o2都是同一个地址,指向同一个对象,修改o2会影响o1
public class classTest2 {
	public static void main(String[] args) {
		Order o1=new Order();
		o1.orderId=1001;
		Order o2=o1;
		System.out.println("o1.OrderId="+o1.orderId+",o2.OrderId="+o2.orderId);
		//o1.OrderId=1001,o2.OrderId=1001
		o2.orderId=1002;
		System.out.println("o1.OrderId="+o1.orderId+",o2.OrderId="+o2.orderId);
		//o1.OrderId=1002,o2.OrderId=1002
	}
}
class Order{
	int orderId;	
}

方法的形参的传递机制:值传递
1.形参:方法定义时,声明的小括号内的参数
实参:方法调用时,实际传递给形参的数据
2.值传递机制:如果参数是基本数据类型,此时实参赋给形参的是,实参真实存储的数据值。如果参数是引用数据类型,此时实参赋给形参的是变量错保存的数据的地址值

基本数据类型的参数传递
基本数据类型的参数传递
引用数据类型的参数传递2
引用数据类型的参数传递
引用数据类型的参数传递2
在这里插入图片描述
练习1

//基本数据类型的参数传递
public class classTest2 {
	public static void main(String[] args) {
		ValueTransTest test=new ValueTransTest();
		int m=10;
		int n=20;
		test.swap(m,n);
		System.out.println("m="+m+",n="+n);//m=10,n=20未交换数值
	}
}
class ValueTransTest{
	public void swap(int m,int n) {
		int temp=m;
		m=n;
		n=temp;
	}
}

内存解析:
在这里插入图片描述
形参m,n在swap结束后被销毁,并不会输出。m和n保持原值。
练习2

//数组的参数传递
public class classTest2 {
	public static void main(String[] args) {
		ValueTransTest test=new ValueTransTest();
		int[]arr=new int[] {1,2,3,5,7,2,4,0};
		for (int i=0;i<arr.length;i++) {
			for(int j=0;j<arr.length-i-1;j++) {
				if(arr[j]>arr[j+1]) {
					test.swap(arr[j],arr[j+1]);
				}
			}		
		}
		for (int i=0;i<arr.length;i++) {
			System.out.print(arr[i]+"\t");//1	2	3	5	7	2	4	0
			//未交换,赋给形参的是arr[i],arr[i+1]的真实数据
		}
	}
}
class ValueTransTest{
	public void swap(int m,int n) {
		int temp=m;
		m=n;
		n=temp;
	}
}
//引用数据类型类型的传递
public class classTest2 {
	public static void main(String[] args) {
		ValueTransTest test=new ValueTransTest();
		Data data=new Data();
		data.m=10;
		data.n=20;
		/*
		int temp=data.m;
		data.m=data.n;
		data.n=temp;
		System.out.println("m="+data.m+",n="+data.n);//m=20,n=10
		*/
		test.swap(data);
		System.out.println("m="+data.m+",n="+data.n);//m=20,n=10
	}
}
class ValueTransTest{
	public void swap(Data data) {
		int temp=data.m;
		data.m=data.n;
		data.n=temp;
	}
}

内存解析:
在这里插入图片描述
swap结束后,局部变形temp和形参data被销毁,但是m和n已经改变。

正确交换数组值得方法

public class classTest2 {
	public static void main(String[] args) {
		ValueTransTest test=new ValueTransTest();
		int[]arr=new int[] {1,2,3,5,7,2,4,0};
		for (int i=0;i<arr.length;i++) {
			for(int j=0;j<arr.length-i-1;j++) {
				if(arr[j]>arr[j+1]) {
					test.swap(arr, j, j+1);
				}
			}		
		}
		for (int i=0;i<arr.length;i++) {
			System.out.print(arr[i]+"\t");//0	1	2	2	3	4	5	7
			//交换,赋给形参的是arr的地址值
		}
	}
}
class ValueTransTest{
	public void swap(int[] arr,int i,int j) {
		int temp=arr[i];
		arr[i]=arr[j];
		arr[j]=temp;		
	}
}

练习3
以下程序的输出值

public class classTest2 {
	public static void main(String[] args) {
		classTest2 test=new classTest2();
		//在一个类中的访问机制: 类中的方法可以直接访问类中的成员变量。
		//但是static访问非static要先new一个对象
		test.first();
	}
	public void first(){
		int i=5;
		Value v=new Value();
		v.i=25;
		second(v,i);
		System.out.println(v.i);        //20	
	}
	public void second(Value v,int i) {
		i=0;
		v.i=20;
		Value val=new Value();
		v=val;
		System.out.println(v.i+" "+i);    //15 0
	}
}
class Value{
	int i=15;
}

内存解析:
在这里插入图片描述
先退出second方法,second中val,i,v被释放,堆空间中的对象没有指针也被释放。然后退出first方法,second中i,v被释放,堆空间中的对象没有指针也被释放。最后释放test指向的对象,结束程序。

补充:String的值传递

public class classTest2 {
	public static void main(String[] args) {
		classTest2 test=new classTest2();
		String s1="hello";
		test.change(s1);
		System.out.println(s1);//hello
	}
	public void change(String s) {
		s="hi~~";
	}
}

内存解析:
在这里插入图片描述
String是存储在方法区内,并且不可变增序列。
扩展练习1
在这里插入图片描述
扩展练习2

int[] arr = new int[] {1,2,3};
System.out.println(arr);//地址值?  [I@15db9742
char[] arr1 = new char[] {'q','a','b','c'};
System.out.println(arr1); //地址值?  qabc
//这是因为println(char)的功能就是遍历

练习4
在这里插入图片描述

public class classTest2 {
	public static void main(String[] args) {
		PassObject p1=new PassObject();
		//p1.printAreas(new Circle(),5);
		Circle c=new Circle();
		//System.out.println(c.radius);//0
		p1.printAreas(c,5);
		//System.out.println(c.radius);//5
	}
}
class Circle{
	double radius;
	public double findArea() {
		return Math.PI*radius*radius;
	}
}
class PassObject{
	public void printAreas(Circle c,int time) {
		System.out.println("Radius\t\tArea");
		for(int i=1;i<=time;i++) {
		 c.radius=i;
			System.out.println(c.radius+"\t"+c.findArea());	
		}
	}
}
/*
 * 
Radius		Area
1.0	3.141592653589793
2.0	12.566370614359172
3.0	28.274333882308138
4.0	50.26548245743669
5.0	78.53981633974483
 */

递归方法
递归方法:一个方法体内调用它自身。
方法递归包含了一种隐式的循环,它会重复执行某段代码,但这种重复执行无须循环控制。递归一定要向已知方向递归,否则这种递归就变成了无穷递归,类似于死循环。

练习1:
n的阶乘

public class classTest2 {
	public static void main(String[] args) {
		classTest2 test=new classTest2();
		int sum=test.getsum(5);
		System.out.println(sum);
	}
	public int getsum(int n){
		if(n==0) {
			return 1;
		}else {return n*getsum(n-1);}
	}
}

练习2
输入一个数据n,计算斐波那契数列(Fibonacci)的第n个值
1 1 2 3 5 8 13 21 34 55
规律:一个数等于前两个数之和
要求: 计算斐波那契数列(Fibonacci)的第n个值,并将整个数列打印出来

public class classTest2 {
	public static void main(String[] args) {
		classTest2 test=new classTest2();
		int sum=test.getsum(6);
		System.out.println(sum);
	}
	public int getsum(int n){
		if(n==1) {
			return 1;
		}else if(n==2) {return 1;}
		else {return getsum(n-1)+getsum(n-2);}
	}
}

练习3
汉诺塔问题

练习4
快排

扩展练习
已知有一个数列: 当n<=0时,f(n) = 1;n>0时,f(n+2)=2*f(n+1) + f(n),求f(10)的需要调用递归的次数。
在这里插入图片描述
可以用前序遍历的方法来计算。
前,中,后序遍历的递归实现

import java.util.Stack;
public class classTest3 {
	public static void main(String[] args)
	{
		TreeNode[] node = new TreeNode[10];//以数组形式生成一棵完全二叉树
		for(int i = 0; i < 10; i++)
		{
			node[i] = new TreeNode(i);//赋值
		}
		for(int i = 0; i < 10; i++)
		{
			if(i*2+1 < 10)
				node[i].left = node[i*2+1];
			if(i*2+2 < 10)
				node[i].right = node[i*2+2];
		}
		
		preOrderRe(node[0]);//0	1	3	7	8	4	9	2	5	6
		System.out.println();
		midOrderRe(node[0]);//7	3	8	1	9	4	0	5	2	6
		System.out.println();
		postOrderRe(node[0]);//7	8	3	9	4	1	5	6	2	0	
		
	}
	
	public static void preOrderRe(TreeNode biTree)
	{//递归实现
		System.out.print(biTree.value+"\t");//0	1	3	7	8	4	9	2	5	6
		TreeNode leftTree = biTree.left;
		if(leftTree != null)
		{
			preOrderRe(leftTree);
		}
		TreeNode rightTree = biTree.right;
		if(rightTree != null)
		{
			preOrderRe(rightTree);
		}
	}
	public static void midOrderRe(TreeNode biTree)
	{//中序遍历递归实现
		if(biTree == null)
			return;
		else
		{
			midOrderRe(biTree.left);
			System.out.print(biTree.value+"\t");
			midOrderRe(biTree.right);
		}
	}
	public static void postOrderRe(TreeNode biTree)
	{//后序遍历递归实现
		if(biTree == null)
			return;
		else
		{
			postOrderRe(biTree.left);
			postOrderRe(biTree.right);
			System.out.print(biTree.value+"\t");
		}
	}
}

class TreeNode//节点结构
{
	int value;
	TreeNode left;
	TreeNode right;
	
	TreeNode(int value)
	{
		this.value = value;
	}
}

4.6 OOP特征一:封装和隐藏

问题的引入:当我们创建一个类的对象以后,我们可以通过“对象.属性”的方式,对对象的属性进行赋值。这里赋值操作要有属性数据类型和存储范围的制约。除此之外,没有其他限制条件。但在实际问题中,我们往往需要给属性加入额外的限制条件。这个条件就不能在属性声明时体现,我们只能通过方法进行限制条件的添加。同时我们需要避免用户再使用“对象.属性”的方式对属性进行赋值,则需要将属性声明为private。

public class classTest2 {
	public static void main(String[] args) {
		Animal a=new Animal();
		a.setLegs(4);
		int legs=a.getLegs();
		System.out.println(legs);//4
		a.setLegs(-1);
		System.out.println(a.getLegs());//0
	}
}
class Animal{
	String name;
	int age;
	private int legs;
	public void setLegs(int l) {
		if(l>=0&&l%2==0) {
			legs=l;
		}else {legs=0;}
	}
	public int getLegs(){
		return legs;
	}
}

封装性的体现:1.将类的属性XXX私化,同时,提供公共的方法来获取getXxx和设置setXxx此属性的值
2.不对外暴露的私有的方法
3.单例模式(构造器私有化)
4.如果不希望类在包外调用,可以将类设置为缺省的。
权限修饰符
在这里插入图片描述
练习
在这里插入图片描述

public class classTest2 {
	public static void main(String[] args) {
		Person a=new Person();
		a.setAge(4);
		int age=a.getAge();
		System.out.println(age);//4
		a.setAge(-1);//输入非法数据
	}
}
class Person{
	private int age;
	/*
	public void setAge(int a) {
		if(a>=0&&a<=130) {
			age=a;
		}else {System.out.println("输入非法数据");}
	}
	*/
	public void setAge(int a) {
		if(a<0||a>130) {
			System.out.println("输入非法数据");
			return;
		}
		age=a;
	}
	public int getAge(){
		return age;
	}
}

4.7 类的成员之三:构造器

构造器的作用:创建对象;初始化对象的属性
说明
1.如果没有显式的定义类的构造器的话,则系统默认提供一个空参的构造器
2.定义构造器的格式:权限修饰符 类名(形参列表){}
3.一个类中定义的多个构造器,彼此构成重载
4.一旦我们显式的定义了类的构造器后,系统就不再提供默认的空参构造器
5.一个类中,至少会有一个构造器

public class classTest2 {
	public static void main(String[] args) {
		//创建类的对象:new+构造器
		Person a=new Person();
		Person b=new Person("Tom");
		Person c=new Person("Tom",9);
	}
}
class Person{
	String name;
	 int age;
	 //构造器
	public Person(){
		System.out.println("Person()....");
		age=4;
	}
	public Person(String n) {
		name=n;
	}
	public Person(String n,int a) {
		name=n;
		age=a;
	}
}

属性赋值的先后顺序:默认初始化,显式初始化,构造器中的赋值,“对象.方法”或“对象.属性”的方式赋值(前三个只执行一次,最后一个赋值可以执行多次)
构造器的权限与类的权限一致
JavaBean是一种Java语言写成的可重用组件。JavaBean:公共的类;有一个无参的公共的构造器;有属性,且有对应的get,set方法。
为什么都要有一个空参的构造器,方便造对象。反射造对象 -空参构造器

4.8 关键字:this

this 关键字的使用:1.this可以用来修饰:属性,方法,构造器 2.this修饰属性和方法:this理解为:当前对象
在类的方法或构造器中,我们可以使用“this.属性”或“this.方法”的方式,调用当前对象属性或方法。但通常情况下,我们都选择省略“this.”。特殊情况下,如果方法的形参和类的属性同名时,我们必须显式的使用“this.变量”的方式,表明此变量是属性,而非形参。

//改善构造器冗余
class Person{
	String name;
	 int age;
	 //构造器
	public Person(){//无参构造器
		System.out.println("新对象实例化");
	}
	public Person(String name) {
		this();//调用本类中的无参构造器
		this.name=name;
	}
	public Person(String name,int age) {
		this(name);//调用有一个参数的构造器
		this.age=age;
	}
}

this 调用构造器
1.我们在类的构造器中,可以显式的使用“this(形参列表)”方式,调用本类中指定的其他构造器
2.构造器中不能通过“this(形参列表)”方式调用自己
3.如果一个类中有n个构造器,则最多有n-1构造器中使用了“this(形参列表)”
4.规定:“this(形参列表)”必须声明在当前构造器的首行
5.构造器内部,最多只能声明一个“this(形参列表)”,用来调用其他的构造器

4.9 关键字:package,import

一、package关键字的使用
1.为了更好地实现项目中类的管理,提供包的概念
2.使用package声明类或接口所属的包,声明在源文件的首行
3.包,属于标识符,遵循标识符的命名规则,规范(xxxyyyzzz)
4.每“.”一次,就代表一层文件目录。
5.同一包下不能命名同名的接口、类;不同的包下,可以命名同名的接口、类。
在这里插入图片描述
二、import关键字的使用
import:导入
1.在源文件中显式的使用import结构导入指定包下的类、接口
2.声明在包的声明和类的声明之间
3.如果需要导入多个结构,则并列写出即可
4.可以使用“xxx.* ”的方式,表示可以导入xxx包下的所有结构。
5.如果使用的类或接口是java.lang包下定义的,则可以省略import结构
6.如果使用的类或接口是本包下定义的,则可以省略import结构
7.如果在源文件中,使用了不同包下的同名的类,则必须至少有一个类需要以全类名的方式显示
8.使用“xxx.*”方式表明可以调用xxx包下的所有结构,但是如果使用的是xxx子包下的结构,则仍需要显示子包的结构
9.import static:导入指定类或接口中的静态结构:属性或方法

import static java.lang.System.*;
import static java.lang.Math.*;
out.println("hello");//out是一个方法
long num=round(123.234);

补充:

public class classTest2 {
	public static void main(String[] args) {
		Account a=new Account();
		Customer c=new Customer();
		c.account=a;
	}
}
class Account{
	int id;
	double balance;
}
class Customer{
	 String firstName;
	String lastName;
	 Account account;
}

内存解析:
在这里插入图片描述

4.10 课后练习

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

public class classTest2 {
	public static void main(String[] args) {
		Bank bank=new Bank();
		bank.addCustomer("Jane", "Smith");
		System.out.println(bank.getNumberOfCustomers());//1
		bank.getCustomer(0).setAccount(new Account(100));
		bank.getCustomer(0).getAccount().deposit(1000);//成功存入1000.0
		bank.getCustomer(0).getAccount().withdraw(2000);//余额不足
		double balance=bank.getCustomer(0).getAccount().getBalance();
		System.out.println(balance);//1100.0
	}
}
class Account{
	private double balance;
	public Account(double balance){
		this.balance=balance;
	}
	public double getBalance(){
		return balance;
	}
	public void withdraw(double amount) {
		if(balance<amount) {
			System.out.println("余额不足");
			return;
		}
		balance-=amount;
		System.out.println("成功取出"+amount);
	}
	public void deposit(double amount) {
		balance+=amount;
		System.out.println("成功存入"+amount);
		
	}
}
class Customer{
	private String firstName;
	private String lastName;
	private Account account;
	public Customer(String f,String l) {
		this.firstName=f;
		this.lastName=l;		
	}
	public Account getAccount() {
		return account;
	}
	public void setAccount(Account account) {
		this.account = account;
	}
	public String getFirstName() {
		return firstName;
	}
	public String getLastName() {
		return lastName;
	}	
}
class Bank{
	private Customer[] customers;
	private int numberOfCustomers;
	public Bank() {
		customers=new Customer[10];//初始化数组
	}
	public void addCustomer(String f,String l) {
		Customer cust=new Customer(f,l);
		customers[numberOfCustomers]=cust;
		numberOfCustomers++;
	}
	public int getNumberOfCustomers() {
		return numberOfCustomers;
	}
	public Customer getCustomer(int index) {
		if(index>=0&&index<numberOfCustomers) {
			return customers[index];
		}else {return null;}

	}
}

内存解析:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值