• 第四章 面向对象(一)


    第四章 面向对象(一)

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

    • 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

  • 相关阅读:
    Struts2整合Spring
    关于碰撞检测的相关信息
    直角三角形
    XNA 3.0初步——自定义游戏循环时间
    XNA 3.0初步——将你的XNA 3.0游戏部署到Zune
    XNA 3.0初步——开始第一个XNA 3.0项目
    创建场景和赛道——概览
    XNA 3.0初步——将你的XNA 3.0游戏部署到另一台PC
    创建场景和赛道——场景绘制
    创建场景和赛道——游戏比较
  • 原文地址:https://www.cnblogs.com/caoj/p/16412153.html
Copyright © 2020-2023  润新知