• 《JAVA程序设计与实例》记录与归纳--类与对象


    类与对象

    概念贴士:

    1.  类必须先定义了才能使用。类是创建对象的模板,创建对象也叫类的实例化。

     

    2.  在Java中,使用new关键字来创建对象,一般有一下3个步骤:

        1)声   明:声明一个对象,包括对象名称和对象类型。

        2)实例化:使用关键字new创建一个对象。

        3)初始化:使用new创建对象时,会调用构造方法初始化对象。

     

    3.  在类实例化的过程中自动执行的方法叫做构造方法,它不需要手动调用。构造方法可以在类实例化的过程中完成一些初始化的工作。构造方法的名称必须与类的名称相同,并且没有返回值。每个类都有构造方法,如果没有显式地为类定义构造方法,Java编译器将会为该类提供一个默认的构造方法。

     

    4.  Java通过修饰符来控制类、属性和方法的访问权限和其他功能,通常放在语句的最前端。

     

    5.  Java的修饰符很多,分为访问修饰符和非访问修饰符。其中访问修饰符也叫访问控制符,是指能够控制类、成员变量、方法的使用权限的关键字。  在面向对象编程中,访问控制符是一个很重要的概念,可以使用它来保护对类、变量、方法和控制方法的访问。

     

    6.  Java支持4种不同的访问权限:

        1)public      共有的,对所有类可见

        2)protected    受保护的,对同一包内的类和所有子类可见

        3)private      私有的,在同一类内可见

        4)默认的      在同一包内可见,默认不使用任何修饰符

     

    6.1  public:公有的

        被声明为public的类、方法、构造方法行业接口能够被任何其他类访问。如果几个相互访问的public类分布在不同的包中,则需要导入相应public类所在的包。由于类的继承性,类所有的公有方法和变量都能被子类继承。

        例子:public static void main(String[] arguments){}

        PS:Java程序main()方法必须是设置成公有的。

     

    6.2  protected:受保护的

        被声明为protected的变量、方法和构造方法能够被同一包中的任意其他类访问,也能够被不同包中的子类访问。protected访问修饰符不能修饰类和接口,方法和成员变量能够声明为protected,但是接口的成员变量和成员方法不能声明为protected。子类能访问protected修饰符声明的方法和变量,这样就能保护不相关的类使用这些方法和变量。

        例子:

     1 public class Dog{
     2     protected void bark(){
     3         System.out.println("汪汪,不要过来!");
     4     }
     5 }
     6 
     7 class Teddy extends Dog{            //泰迪
     8     protected void bark(){
     9         System.out.println("汪汪,我好怕,不要跟着我!");
    10     }
    11 }

        PS:如果把bark()方法声明为private,那么除了Dog之外的类将不能访问该方法。如果把bark()方法声明为public,那么所有的类都能够访问该方法。如果只想让该方法对其所在类的子类可见,则将该方法声明为protected即可。

    6.3  private:私有的

        私有访问修饰符是最严格的访问控制级别,所以被声明为private的方法、变量和构造方法只能被所属类访问,并且类和接口不能声明为private。  声明为私有访问类型的变量只能通过类中公共的getter/setter方法被外部类访问。private访问修饰符的使用主要用来隐藏类的实现细节和保护类的数据。

        例子:

     1 public class Dog{
     2     private String name;
     3     private int age;
     4     public String getName(){
     5         return name;
     6     }
     7     public void setName(String name){
     8         this.name=name;
     9     }
    10     public int getAge(){
    11         return age;
    12     }
    13     public void setAge(int age){
    14         this.age=age;
    15     }
    16 }

        PS:程序中,Dog类中的name、age变量为私有变量,所以其他类不能直接得到和设置该变量的值。为了使其他类能够操作该变量,程序中定义了两对public方法,getName()/setName()和getAge()/setAge(),用来获取和设置私有变量的值。

        PS:this是Java中的一个关键字,在类中定义访问私有变量的方法,习惯上是这样命名的:在变量名称前面添加get或者set,并将变量的首字母大写。上述两对方法由于经常使用,也有特定的称呼,称为getter和setter方法。

    6.4  默认的:不使用任何关键字

        不适用任何修饰符声明的属性和方法,对同一个包内的类是常见的。接口的变量都隐式声明为public static final(final为非访问修饰符之一),而接口里的方法默认情况下访问权限为public。

    6.5  访问控制符使用小总结:

    1. 访问控制符可以令我们便于控制代码的权限。

        1)当需要让自己编写的类被所有的其他类访问时,就可以将类的访问控制符声明为public。

        2)当需要让自己的类只能被自己的包中的类访问时,就可以省略访问控制符。

        3)当需要控制一个类中的成员数据时,可以将这个类中的成员数据访问控制符设置为public、protected或者省略。

      2.  方法继承的规则。

        1)父类中声明为public的方法在子类中也必须为public。

        2)父类中声明为protected的方法在子类中要么声明为protected,要么声明为public,不能声明为private。

        3)父类中默认修饰符声明的方法,能够在子类中声明为private。

        4)父类中声明为private的方法,不能被继承。

    7.  在Java中,变量的作用域分为4个级别,即类级、对象实例级、方法级和块级。(详见实例3-4)

        1)类级变量又称为全局级变量或者静态变量,需要使用static关键字修饰,类级变量在类定义后就已经存在,占用内存空间,可以通过类名来访问,不需要实例化。

        2)对象实例级变量就是成员变量,实例化后才会分配内存空间,才能访问。

        3)方法级变量是在方法内部定义的变量,是局部变量。

        4)块级变量是定义在一个块内部的变量,变量的生存周期就是这个块,出了这个块则变量消失,如if、for语句的块。块是指由大括号(花括号)包围的代码。

    8.  在Java中,this可以在类里引用这个类的属性和方法。this关键字用来表示当前对象本身,或当前类的一个实例,通过this关键字可以调用本对象的所有方法和属性。(详见实例3-5)

    9.  成员变量与方法内部的变量重名时,希望在方法内部调用成员变量,可以通过使用this关键字区分同名变量。(详见实例3-6)

    10.  在构造函数中通过this引用来调用另一个构造函数,也就是相当于调用本类的其他构造方法,它必须作为构造方法的第一句(即作为方法名初始化对象)。(详见实例3-7)

    11.  需要在某些完全分离的类中调用一个方法,并将当前对象的一个引用作为参数传递时,可以使用this关键字,作为参数传递。(详见实例3-8)

    12.  在Java中

    ,同一个类中的多个方法可以有相同的名字,但参数列表不同,这被称为方法重载(method overloading)。重载是面向对象的一个基本特性。  参数列表又叫参数签名,包括参数的类型,参数的个数与参数的顺序,只要有一个不同就叫做参数列表不同。(详见实例3-9)

    13.  1.重载说明:

        1)参数列表不同包括:个数不同、类型不同和顺序不同。

        2)仅参数变量名称不同是不可以的(毕竟那只是形参)。

        3)与成员方法一样,构造方法也可以重载。

        4)声明为final的方法不能被重载(感兴趣可以查询final这个非访问修饰符)。

        5)声明为static的方法不能被重载,但是能够被再次声明。

        2.方法的重载规则:

        1)方法名称必须相同。

        2)参数列表必须不同。

        3)方法的返回类型可以不同,也可以相同。

        4)仅仅返回类型不同不足以成为方法的重载。

        3.方法重载的实现:方法名称相同时,编译器会根据调用方法的参数个数、参数类型等逐个去匹配,以选择对应的方法,如果匹配失败,则编译器报错,这叫重载分辨。

    14.  Java为每种基本数据类型分别设计了对应的类,实现数据间类型转化,这些类被称之为包装类(Wrapper Classes)。

    15.  封装就是将属性私有化,提供公有的方法访问私有的属性。其实现步骤如下:

        1)修改属性的可见性限制对属性的访问。

        2)为每个属性创建一对赋值方法和取值方法,用于对这些属性的访问。

        3)在赋值和取值方法中,加入对属性的存取限制。

    16.  为了实现良好的封装性,通常将类的成员变量声明为private,再通过public的方法对这个变量进行访问。对一个变量的操作,一般是读取和赋值操作,下面分别定义两个方法来实现这两种操作,一个是getXxx()方法(Xxx表示要访问的成员变量的名字),用来读取这个成员变量操作;另外一个是setXxx()方法,用来对这个成员变量赋值。(详见实例3-10)

    代码解释:

    实例3-1

     1 package duke.example.ch3;
     2 
     3 public class Dog{
     4     String name;                    //名字
     5     int age;                            //年龄
     6 
     7     void bark(){                    //汪汪叫
     8         System.out println("汪汪,不要过来");
     9     }
    10 
    11     void hungry(){                //饥饿
    12         System.out.println("主任,我饿了");
    13     }
    14 }

    代码说明: 代码行.3中 public是类的修饰符,表明该类是公共类,可以被其他类访问。class是定义类的关键字,Dog是类名称。

          代码行.4-5中 name、age是类的成员变量,也叫属性。

          代码行.7-9中 bark()是类中的函数,也叫方法,即定义犬吠这个方法。

          代码行.11-13中 hungry()是类中的函数,也叫方法。

    PS:一个类的变量可以包含以下类型变量。

    • 局部变量:在方法或者语句块中定义的变量被称为局部变量。变量声明和初始化都是在这个方法中,方法结束后,变量就会自动销毁。
    • 成员变量:在类中、方法体之外定义的变量。这种变量在创建变量的时候实例化(分配内存)。成员变量可以被类中的方法和特定类的语句访问。
    • 类 变 量 :也是在类中、方法体之外定义的变量,但必须声明为static类型。static也是修饰符的一种。

     

    实例3-2

     1 package duke.example.ch3;
     2 
     3 public class Dog{
     4     String name;                    //名字
     5     int age;                            //年龄
     6 
     7     Dog(String name,int age){    //构造方法,没有返回值
     8         this.name=name;
     9         this.age=age;
    10         System.out.println(name+“感谢主人天天带我玩耍!”);
    11     }
    12 
    13      void bark(){                    //汪汪叫
    14         System.out println("汪汪,不要过来");
    15     }
    16 
    17     void hungry(){                //饥饿
    18         System.out.println("主任,我饿了");
    19     }
    20 
    21     public static void main(String[] args){
    22         //创建对象时传递的参数要与构造方法参数列表对应
    23         Dog myDog=new Dog("卡拉",3);
    24         System.out.println("我是一只小狗,我的名字叫"+name+",我"+age+"岁了!");
    25     }
    26 }

    输出结果:

            卡拉感谢主人天天带我玩耍!
            我是一只小狗,我的名字叫卡拉,我3岁了!

    代码说明: 代码行.7-9中 定义包含两个参数name和age的构造函数,构造方法的名称必须与类的名称Dog相同。构造方法不能有返回值,因为没有变量来接收返回值。

          代码行.23中 构造方法不能被显示调用,在类Dog实例化的过程中自动执行了。

    代码执行顺序:

      1)先运行到代码行.21。这是程序的入口。

      2)然后运行代码行.23。这里要创建一个Dog,就要调用Dog的构造方法。

      3)运行到代码行.7。注意接下来并不是运行代码行.8,初始化一个类,必须先初始化他的属性。

      4)因此运行到代码行.4。然后是代码行.5。

      5)属性初始化后,才回到构造方法,执行里面的代码,也就是代码行.8-10。

      6)然后是代码行.11。表示创建一个Dog实例完成。

      7)然后回到main()方法中执行代码行.23-24。

      8)最后是代码行.25。main()方法执行完毕。

    书上说作为程序员,应该知道程序的基本运行过程,否则不利于编写代码与进步,其实这是有道理的。在一个程序中,你看到的深度决定了你编程水平的上限。

     

    实例3-3

     1 package duke.example.ch3;
     2 
     3 public class Dog{
     4     String name;                    //名字
     5     int age;                            //年龄
     6 
     7     Dog(String name,int age){    //构造方法,没有返回值
     8         this.name=name;
     9         this.age=age;
    10         System.out.println(name+“感谢主人天天带我玩耍!”);
    11     }
    12 
    13      void bark(){                    //汪汪叫
    14         System.out println("汪汪,不要过来");
    15     }
    16 
    17     void hungry(){                //饥饿
    18         System.out.println("主任,我饿了");
    19     }
    20 
    21     public static void main(String[] args){
    22         //创建对象时传递的参数要与构造方法参数列表对应
    23         Dog myDog=new Dog("卡拉",3);
    24         //访问成员变量
    25         String name=myDog.name;
    26         int age=myDog.age;
    27         System.out.println("我是一只小狗,我的名字叫"+name+",我"+age+"岁了!");
    28         //访问方法
    29         myDog.bark();
    30         myDog.hungry();
    31     }
    32 }

    输出结果:

            卡拉感谢主人天天带我玩耍!
            我是一只小狗,我的名字叫卡拉,我3岁了!
            汪汪,不要过来!
            主人,我饿了!

    代码说明: 代码行.26-27中 通过点号(.)访问变量name和age。

          代码行.29-30中 通过点号(.)访问成员方法bark()和hungry()。

     

    实例3-4

     1 package duke.example.ch3;
     2 
     3 public class Scope{
     4     public static String name="爪哇岛旅游攻略";        //类级变量
     5     public int i;                                                        //对象实例级变量
     6 
     7     //属性块,在类初始化属性时候运行
     8     {
     9         int j=2;                                                            //块级变量
    10     }
    11 
    12     public void test(){
    13         int j=3;                                                            //方法级变量
    14         if(j==3){
    15             int k=5;
    16         }
    17         //这里不能访问块级变量,块级变量只能在块内部访问
    18         System.out.println("name="+name+",i="+i+",j="+j);
    19     }
    20 
    21     public static void main(String[] args){
    22         //不创建对象,直接通过类名访问类级变量
    23         System.out.println(Scope.name);
    24         //创建对象并访问它的方法
    25         Scope.scope=new Scope();
    26         scope.test();
    27     }
    28 }

    输出结果:

            爪哇岛旅游攻略
            name=爪哇岛旅游攻略,i=0,j=3

    代码说明: 代码行.4中 使用static关键字定义类级字符串变量name。

          代码行.12-19中 定义方法test(),方法内部定义了方法级变量和块级变量。

    PS:  1)方法内部除了能访问方法级的变量,还可以访问类级和实例级的变量。

         2)块内部能够访问类级、实例级变量,如果块被包含在方法内部,它还可以访问方法级的变量。

         3)方法级和块级的变量必须被显式初始化,否则不能访问。

     

     实例3-5

     1 package duke.example.ch3
     2 
     3 public class ThisDemo1 {
     4     public int x=10;
     5     public int y=15;
     6 
     7     public void sum() {
     8         int z=this.x+this.y;
     9         System.out.println("x+y="+z);
    10     }
    11  
    12     public static void main(String[] args) {
    13         ThisDemo1 thisdemol=new ThisDemo1();
    14         thisdemo1.sum();
    15     }
    16 }

    输出结果:

            x+y=25

    代码说明: 代码行.4-5中 定义成员变量x和y。

          代码行.8中 通过this点取成员变量。

    PS:上面程序中,thisdemol时ThisDemol类的一个实例,this和thisdemol等价,执行int z=this.x+this.y;,就相当于执行int z=thisdemol.x+thisdemol.y;。

    PS:this只有在类实例化后才有意义。

     

    实例3-6

     1 package duke.example.ch3;
     2 
     3 public class ThisDemo2 {
     4     public String name;
     5     public int age;
     6 
     7     public ThisDemo2(String name,int age) {
     8         this.name=name;
     9         this.age=age;
    10     }
    11 
    12     public void say() {
    13         System.out.println("网站的名字是"+name+",已经成立了"+age+"年");
    14     }
    15 
    16     public static void main(String[] args) {
    17         ThisDemo2 thisdemo2=new ThisDemo2("www.baidu.com",15);
    18         thisdemo2.say();
    19     }
    20 }

    输出结果:

            网站的名字是www.baidu.com,已经成立了15年

    代码说明: 代码行.7-10中 成员变量与方法内部的变量重名时,通过this引用调用成员变量。  形参的作用域是整个方法体,是局部变量。在ThisDemo2(String name,int age)中,形参与成员变量重名,如果不使用this,访问到的就是局部变量name和age,而不是成员变量。

          代码行.12-14中 在say()中没有使用this,因为成员变量的作用域是整个实例,当然也可以加上this。

            eg:System.out.println("网站的名字是"+this.name+",已经成立了"+this.age+"年"):

    PS:Java默认将所有成员变量和成员方法与this关联在一起,因此使用this在某些情况下是多余的。

     

    实例3-7

     1 package duke.example.ch3;
     2 
     3 public class ThisDemo3 {
     4     public String name;
     5     public int age;
     6 
     7     public ThisDemo3() {
     8         this("www.baidu.com",15);
     9     }
    10 
    11     public ThisDemo3(String name,int age) {
    12         this.name=name;
    13         this.age=age;
    14     }
    15 
    16     public void say() {
    17         System.out.println("网站的名字是"+name+",已经成立了"+age+"年");
    18     }
    19 
    20     public static void main(String[] args) {
    21         ThisDemo3 thisdemo3=new ThisDemo3();
    22         thisdemo3.say();
    23     }
    24 }

    输出结果:

            网站的名字是www.baidu.com,已经成立了5年

    代码说明: 代码行.7-9中 在构造方法中,this调用另一个构造方法,调用动作必须置于最起始的位置。注意,不能在构造方法以外的任何方法内调用构造方法,在一个构造方法内只能调用一个构造方法。

    PS:上述代码设计方法重载,即Java允许出现多个同名方法,只要参数不同即可。

     

    实例3-8

     1 package duke.example.ch3;
     2 
     3 public class ThisDemo4 {
     4 
     5     public static void main(String[] args) {
     6         B b=new B(new A());
     7     }
     8 }
     9 
    10 class A {
    11     public A() {
    12         new B(this).print();
    13     }
    14 
    15     public void print() {
    16         System.out.println("Hello from A!");
    17     }
    18 }
    19 
    20 class B {
    21     A a;
    22 
    23     public B(A a) {
    24         this.a=a;
    25     }
    26 
    27     public void print() {
    28         a.print();
    29         System.out.println("Hello from B!");
    30     }
    31 }

    输出结果:

            Hello from A!
            Hello from B!

    代码说明: 代码行.12中 匿名对象就是没有名字的对象。如果对象只是用一次,就可以作为匿名对象,代码中new B(this).print();等价于(new B(this)).print();,先通过new B (this)创建一个没有名字的对象,再调用它的方法。

     

    实例3-9

     1 package duke.example.ch3;
     2 
     3 public class Overload {
     4     //一个普通的方法,不带参数的
     5     void test() {
     6         System.out.println("No parameters");
     7     }
     8 
     9     //重载上面的方法,并且带了一个整型参数
    10     void test(int a) {
    11         System.out.println("a:"+a);
    12     }
    13 
    14     //重载上面的方法,并且带了两个整型参数
    15     void test(int a,int b) {
    16         System.out.println("a and b:"+a+" "+b);
    17     }
    18 
    19     //重载上面的方法,并且带了一个双精度参数
    20     double test(double a) {
    21         System.out.println("double a:"+a);
    22         return a*a;
    23     }
    24 
    25     public static void main(String[] args) {
    26         Overload overload=new Overload();
    27         overload.test;
    28         overload.test(2);
    29         overload.test(2,3);
    30         overload.test(2,0);
    31     }
    32 }

    输出结果:

            No parameters
            a:2
            a and b:2 3
            double a:2.0

    PS:重载就是在一个类中,有相同的函数名称,但形参不同的函数。重载的结果,可以让一个程序段减少代码和方法的种类。

     

    实例3-10

     1 package duke.example.ch3;
     2 
     3 public class Person {
     4     //封装属性:将属性设置为私有
     5     private String name;
     6     private int age;
     7 
     8     public  String getName() {                //外部通过此方法访问name属性
     9         return name;
    10     }
    11 
    12     public void setName(String name) {    //该方法是外部赋值私有属性name
    13         this.name=name;
    14     }
    15 
    16     public int getAge() {                            //外部通过此方法访问age属性
    17         return age;
    18     }
    19 
    20     public void setAge(int age) {                //该方法使外部赋值私有属性age
    21         shis.age=age;
    22     }
    23 
    24     void say() {                                            //此方法可以被外部直接调用使用
    25         System.out.println("我叫"+name+",今年"+age+"岁了!");
    26     }
    27 
    28     public static void main(String[] args) {
    29         Person person=new Person();    //实例化person类
    30         person.setName("小芳");                    //通过开放方法给实例化对象的name属性赋值
    31         person.setAge(22);                            //通过开放方法给实例化对象的age属性赋值
    32         person.say();                                    //通过实例化对象的方法
    33     }
    34 }

    输出结果:

            我叫小芳,今年22岁了!

    代码说明: 代码行.5-6中 private是修饰符表示私有化,这就封装了类的属性,封装后外部不能直接使用该属性。

          代码行.7-22中 对外用标准的set/get方法修改/读取属性name和age的值。

          代码行.24中 定义方法say(),该方法可以被外部直接调用使用。

    PS:封装的优点:

        1)隐藏类的实现细节。

        2)让使用者只能通过实现制定好的方法访问数据,可以方便地加入控制逻辑,限制对属性的不合理操作。

        3)便于修改,增强了代码的可维护性。

    总结:这一部分主要谈到了Java的类及其相关基础应用。另外,类的继承和多态是其高阶应用。

  • 相关阅读:
    arthas命令ognl视频演示
    arthas命令sc和sm视频演示
    混合Java函数和Groovy闭包
    Mock System.in和检查System.out
    arthas命令logger动态修改日志级别--视频演示
    删除List中null的N种方法--最后放大招
    ovs安装教程
    win10中安装与配置maven
    win10系统中按顺序安装jdk、tomcat
    win10系统中按顺序安装jdk、tomcat
  • 原文地址:https://www.cnblogs.com/Tiancheng-Duan/p/6676330.html
Copyright © 2020-2023  润新知