第四章 面向对象(一)
学习面向对象的三条主线:
- Java类及类的成员:属性,方法,构造器,代码块,内部类
- 面向对象的三大特征:封装性,继承性,多态性,(抽象性)
- 其它关键字:this,super,final
4.1面向过程与面向对象
面向过程:强调的是功能行为,以函数为最小单位,考虑怎么做。
面向对象:将功能封装进对象,强调具备了功能的对象,以类/对象为最小单位,考虑谁来做。
4.2Java基本元素:类和对象
类:对一类事物的描述,是抽象的、概念上的定义
对象:实际存在的该类事物的每个个体,因而也称为实例(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 calssTest1{
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)+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(staus,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
*@date
*@param arr 对象数组
*/
public void print(Student[] arr){
for(int i=0;i<arr.length;i++){
System.out.println(arr[i].info());
}
}
/**
*@Description 找到对应年级的学生
*@auther
*@date
*@param state
*/
/*
//方式1 getindex
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;
}
*/
//方式2 getindex
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
*@date
*@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
可变个数的形参
Jdk5.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 calssTest2{
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.值传递机制:如果参数是基本数据类型,此时实参赋给形参的是,实参真实存储的数据值。如果参数是引用数据类型,此时实参赋给形参的是变量保存的数据的地址值
基本数据类型的参数传递
引用数据类型的参数传递1
引用数据类型的参数传递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 6 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=dara.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
}
}
calss Value{
int i=15;
}
内存解析:
先退出second方法,second中val,i,v被释放,堆空间中的对象没有指针也被释放。然后退出first方法,second中i,v被释放,堆空间中的对象没有指针也被释放。最后释放test指向的对象,结束程序。
补充:String的值传递
public class calssTest2{
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.redius);//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.pit.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(10)的需要调用递归的次数
可以用谦虚遍历的方法来计算
前,中,后序遍历的递归实现
import java.util.Stack;
public calss 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.6OOP特征一:封装和隐藏
问题的引入:当我们创建一个类的对象后,我们可以通过”对象.属性“的方式,对对象的属性进行赋值。这里赋值操作要有属性数据类型和存储范围的制约。除此之外,没有其他限制条件。但在实际问题中,我们往往需要给属性加入额外的限制条件。这个条件就不能在属性声明时体现,我们只能通过方法进行限制条件的添加。同时我们需要避免用户再使用”对象.属性“的方式对属性进行赋值,则需要将属性声明为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 seLegs(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 classTesr2{
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.00
}
}
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 gerLastName(){
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 gerNumberOfCustomers(){
return numberOfCustomers;
}
public Customer getCustomer(int index){
if(index>=0&&index<numberOfCustomers){
return customers[index];
}else{return null;}
}
}
内存解析:
转载:https://blog.csdn.net/alyja/article/details/107017910