zoukankan      html  css  js  c++  java
  • 构造方法、This关键字、静态与封装的特性与作用

    1.构造方法

    构造方法是一种特殊的方法,专门用于构造/实例化对象。

    构造方法根据是否有参数分为无参构造方法和有参构造方法。

    1.1无参构造方法

    无参构造方法就是构造方法没有任何参数。无参构造方法在创建(new class类名())时调用;无参构造方法一般用于给属性赋默认值。语法:

    [修饰符]  类名(){
    
      ....... 
    
    }

    例如:

     1 public class Dog{  
     2     
     3     String name;
     4     int health;
     5     int love;
     6     String strain;
     7     
     8     public Dog(){    //无参构造方法
     9     System.out.println("构造方法"); 
    10 health = 100; 11 love = 0; 12  } 13 14 }

    如果开发中没有定义无参构造方法,jvm(虚拟机)默认给类分配一个无参构造方法。

    1.2有参构造方法

    当构造/实例化对象时,可以向方法中传递参数,这样子构造的方法叫有参构造方法。

    语法:

    [修饰符] 类名(Type arg1,Type arg2,…){
        // 初始化代码
    }

    注:有参构造方法与无参构造方法是方法重载。

    1.2.1有参构造常见的问题

    如果一个类中提供了有参构造的方法,则JVM(虚拟机)中就不再给该类分配无参构造。

    例如:

    public class Dog{
       String name;
        int health;
        int love;
        String strain;
        
        public Dog(String _name,int _health,int _love,String _strain){  //定义了一个有参构造方法但没有定义无参构造方法
            name = _name;
            health = _health;
            love = _love;
            strain = _strain;
        }
     1 public class TestCar{
     2     public static void main(String[] args){
     3         Dog dog = new Dog();   //调用无参构造方法
     4         dog.name = name;
     5         dog.health = 100;
     6         dog.love = 0;
     7         dog.strain = strain;
     8 
     9 
    10         }
    11 }                        

    运行结果出错:此时jvm不在默认分配无参构造方法

    注意:在开发过程中,如果开发者提供了有参构造方法,一定要习惯性的提供无参构造。

     2.This关键字

    对象初始化内存图

    对象初始化内存图中的方法区位于栈和堆内存的上方,用于保存class和各种方法,对象初始化的过程中最先把class加载该区域,读取class文件中定义的属性和方法,根据定义的属性计算申请内存需要的字节数。

    然后用 new在堆中申请内存并初始化内存。并在堆中生成This关键字,This中存放的是该对象本身的地址,也就说当调用This关键字时,还是指向对象本身。this可用于访问本对象属性,同时解决局部变量和成员变量同名的问题(成员变量可以用this.成员变量名代替)。

    例如

    1 public Dog2(String name,int health,int love,String strain){
    2 System.out.println("this:"+this);
    3     this.name = name;  //this.name代表的就是成员变量(成员属性),name代表的是你输入名。
    4     this.health = health;
    5     this.love = love;
    6     this.strain = strain;
    7 }

    通过打印this中的引用,可以看出对象dog和this指向同一内存。

    一般而言,dog用于类的外部,this用于类的内部。因为类的内部根本不知道 car 变量名的存在。

    方法的调用内存图

    因为在方法中调用了该对象的属性,我们可以用This指向该对象,可以更加快捷的找到其属性值。

    1 public void showInfo(){
    2         System.out.print("我的名字叫"+this.name); //this.属性名 访问
    3         System.out.print(",健康值"+this.health);
    4         System.out.print(",亲密度"+this.love);
    5         System.out.println(",我是一只"+this.strain); 
    6 }

    总结:

    [1] this调用属性

    [2] this调用方法

    [3] this调用本类的构造方法。形如:

     1 public Dog(String name,int health,int love){
     2         this.setName(name);       //调用方法
     3         this.setHealth(health);
     4         this.setLove(love);
     5     }
     6     
     7 
     8     public Dog(String name,int health,int love,String strain){
     9         //this.setName(name);
    10         //this.setHealth(health);
    11         //this.setLove(love);
    12         
    13         // this调用本类的其他构造方法
    14         this(name,health,love);  //调用本类的
    15         this.setStrain(strain);
    16         
    17         // showInfo();
    18         //this.showInfo();
    19     }

    3.静态(static)

    static 关键字表示静态,可以修饰变量,也可以修饰方法。一个类中包含静态成员(静态变量和静态方法)和实例成员(实例变量也叫属性和实例方法)

    下面有这样的一个简单的需求可用static实现

    需求:统计汽车工厂生成了多少量车?

    ð  统计工厂生成了多少量汽车的功能应该放到类功能上,不应该属于某个对象。

    ð  声明一个变量用于统计个数,这个变量应该被类的实例共享。(static)

    ð  被类的实例共享的区域在方法区(Car.class)

    ð  用static关键字声明这样的变量

     1 public class Car{
     2     String brand;
     3     String type;
     4     int price;
     5     static int count; //静态变量的使用方法
     6     public Car(){
     7         count = 0;
     8     }
     9     
    10     public Car(String brand,String type,int price){
    11         this.brand = brand;
    12         this.type = type;
    13         this.price = price;
    14         count++;
    15         showInfo();
    16     
    17     }
    18     
    19     public void showInfo(){
    20         System.out.println("车辆信息:");
    21         System.out.println("品牌:"+this.brand);
    22         System.out.println("型号:"+this.type);
    23         System.out.println("价格:"+this.price);
    24         System.out.println("我是第"+Car.count+"辆车"); //静态变量的访问方式
    25     
    26     
    27 
    28     }
    29 }
     1 public class TestCar{
     2     public static void main(String[] args){
     3         Car car1 = new Car("奔驰","漏油GL300",66);
     4         
     5         
     6         
     7         Car car2 = new Car("奔驰","漏油GL400",66);
     8         
     9         
    10     }
    11 }

    从运行效果图可以我们看出定义的静态变量count并属于哪一个对象,他是属于类所有的,类中的所有对象都可以访问。其区别于其它实例变量(brand、type、price)归实例(对象)所有,每个不同的对象都可以赋不同的属性值,各个对象是之间没有什么联系的。下面我们来详细认识什么是静态变量。

    3.1静态变量

    static 修饰的变量称为静态变量/静态属性,语法:

    static 类型 变量名称 [= 初始值]

    静态变量归类所有,也叫类变量,分配在方法区(共享区)中的静态区,可以被类的实例(对象)共享访问。

    内存图

    静态变量的访问方法为:

    [1] 类名.静态变量(推荐):更好的说明静态变量归类所有

    [2] 对象.静态变量

    3.2静态方法

    用static修饰的方法我们称为静态方法。使用的语法:

    [修饰符] static 返回值类型 方法名(arg…){
    }

    静态方法也归类所有,调用形式和访问静态变量一样。

    [1] 类名.方法名() (推荐)

    [2] 对象.方法名()

    静态方法在使用过程中遇到的常见问题:

    用静态方法访问实例变量

    public class Car{
        String brand;
        String type;
        int price;
        static int count;
        public Car(){
            count = 0;
        }
        
        public Car(String brand,String type,int price){
            this.brand = brand;
            this.type = type;
            this.price = price;
            count++;
            showInfo();
        
        }
        
        public void showInfo(){
            System.out.println("车辆信息:");
            System.out.println("品牌:"+this.brand);
            System.out.println("型号:"+this.type);
            System.out.println("价格:"+this.price);
            System.out.println("我是第"+Car.count+"辆车");
        }
        public static int getCarCount(){
            //定义一个静态方法访问实例变量
            System.out.println("价格:"+this.price);
        }
        
    }

    运行结果:

    用静态方法访问实例方法

    public static int getCarCount(){
            //定义一个静态方法访问实例变量
            //System.out.println("价格:"+this.price);
            //静态方法访问实例方法
            this.showInfo();
        }

    运行结果:

    总结:可以看出通过静态方法并不能访问实例成员(实例变量与实例方法);但是实例方法却可以访问静态成员(静态变量、静态方法);

    通过静态方法可以访问静态变量

    public static int getCarCount(){
            //定义一个静态方法访问实例变量
            //System.out.println("价格:"+this.price);
            //静态方法访问实例方法
            //this.showInfo();
            //返回一个静态变量count
            return Car.count;
            
        }
    public class TestCar{
        public static void main(String[] args){
            Car car1 = new Car("奔驰","漏油GL300",66);
            
            
            
            Car car2 = new Car("奔驰","漏油GL400",66);
            System.out.println(Car.getCarCount());   //调用静态方法并把返回值打印出来
            
            
        }
    }

    运行结果:

    3.3静态常量

    在程序运行过程中,如果一个量的值不会发生改变,可以把该量声明为静态常量,用static final修饰。

     1 public class Penguin{
     2     
     3     private String name;
     4     private int health;
     5     private int love;
     6     private String gender;
     7     
     8     static final String SEX_MALE = "雄";
     9     static final String SEX_FEMALE = "雌";
    10 
    11 ....
    12 }

    作用:方便日后修改代码,减少重复操作。

    4.类的加载机制

    为什么:[1]实例方法可以访问静态成员。

        [2]静态方法不能访问非静态成员。

    当实例化一个对象时(Car car  = new Car(…);)jvm首先把Car.class加载到方法区,然后

    [1]读取Car.class 根据声明的成员变量计算申请内存需要的字节数

    [2]读取Car.class 中的静态成员,给静态变量在方法区分配空间并初始化。

    接着new Car 申请内存得到一个car对象,此时才有对象的空间。showInfo才可以通过car对象调用。

    也就是说程序运行时是先给静态变量分配空间初始化,那时的对象还没在堆中分配有空间(通俗来说还没产生对象),这时怎么可能调用呢!

    5.小结

    6.封装

    封装:将类的某些信息隐藏在类内部,不允许外部程序直接访问,而是通过该类提供的方法来实现对隐藏信息的操作和访问。

    封装的步骤:

    [1]属性私有化

    [2]提供公共的设置器和访问器

    [3]在设置器和访问器中添加业务校验逻辑

     1 public class Penguin{
     2     String name;
     3     // 【1】private 私有的,对外不可见
     4     private int health;
     5     int love;
     6     String gender;
     7      // 【2】提供公共的设置器(setter)和访问器(getter)
     8     public void setHealth(int health){
     9          // 【3】逻辑校验
    10         if(health <0){
    11             this.health = 60;
    12             System.out.println("健康不合法");
    13         }else{
    14             this.health = health;
    15         }
    16     }
    17     public int getHealth(){
    18         return this.health;
    19     }
    20     
    21     public Penguin(){
    22         
    23     }
    24     public Penguin(String name,String gender){
    25         this.name = name;
    26         this.gender = gender;
    27     }
    28     public Penguin(String name,String gender,int health,int love){
    29         this(name,gender);
    30         this.setHealth(health);
    31         this.love = love;
    32     }
    33     
    34     public void showInfo(){
    35         System.out.print("我的名字叫"+this.name);
    36         System.out.print(",健康值"+this.health);
    37         System.out.print(",和主人的亲密度"+this.love);
    38         System.out.println(",性别"+this.gender);
    39         
    40     }
    41 }
     1 public class Test01{
     2     public static void main(String[] args){
     3         //new 得到构造方法(调用构造方法)
     4        // Penguin penguin = new Penguin("美美","Q妹");
     5         //penguin.showInfo();
     6         Penguin penguin02 = new Penguin("壮壮","Q仔",-10,10);
     7         penguin02.showInfo();
     8         //Penguin penguin03 = new Penguin();
     9         //penguin03.setHealth(-10);
    10         //penguin03.showInfo();
    11     }
    12 }

    运行结果:

    从打印结果可以看出,当你输入的健康值小于0时,经过你设定的逻辑校验时,会重新分配默认60。

  • 相关阅读:
    sqlserver中判断表或临时表是否存在
    Delphi 简单方法搜索定位TreeView项
    hdu 2010 水仙花数
    hdu 1061 Rightmost Digit
    hdu 2041 超级楼梯
    hdu 2012 素数判定
    hdu 1425 sort
    hdu 1071 The area
    hdu 1005 Number Sequence
    hdu 1021 Fibonacci Again
  • 原文地址:https://www.cnblogs.com/ruckly/p/10743432.html
Copyright © 2011-2022 走看看