第四章 面向对象(一)

第四章 面向对象(一) 学习面向对象的三条主线:Java类及类的成员:属性,方法,构造器,代码块,内部类 面向对象的三大特征:封装性,继承性,多态性,(抽象性

第四章 面向对象(一)

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

  • 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