Java基础课程-面向对象

来源:互联网 发布:福利资源博客源码 编辑:程序博客网 时间:2024/05/21 05:40

1.上章回顾与预习检查

1.1 上章回顾

  1. 什么是变量?
  2. 什么是表达式?
  3. 都有哪些数据类型?
  4. 流程控制包括哪些?
  

1.2 预习检查

  1. 什么是类?
  2. 什么是对象?对象与类的关系?
  3. 说说对构造函数的理解?
  4. 说说对语句块的理解?

2. 本章任务

  1. 实现初始化块代码的编写
  2. 实现静态化块代码的编写
  3. 实现静态方法代码的编写
  4. 利用可变参数求1到10的和

3. 本章内容

  1. 类
  2. 对象
  3. 构造函数
  4. 语句块
  5. 成员属性
  6. 方法(成员方法、静态方法)
  7. 类的隐藏与封装


3.1 类

3.1.1 类的概述

描述:类是客观存在的,抽象的,概念的东西。
不能将所谓的一个事物描述成一类事物,如一只鸟不能称为鸟类,如果需要对一类事物统称,就不得不说明类这个概念。

类就是对一类事物的统称,如果将现实世界中的一个事物抽象成对象,类就是这类对象的统称,如鸟类、家禽类、人类等。

类是现实世界或思维世界中的实体在计算机中的反映,它将数据以及这些数据上的操作封装在一起

3.1.2 类的声明

类的声明:类的实现包括两部分:类声明和类体.
基本语法为:

// 语法格式:  <修饰符> class <类名> <extends SuperclassName> <implements interfaceNameList>{     <成员变量声明>                  <静态块声明>     <语句块声明>       <构造函数声明>    <成员方法声明>    <内部类声明>    <接口声明>     ......}

3.1.3 类修饰符的说明

修饰符 含义 abstract 该类为抽象类(不能用new实例化一个对象) final 该类为最终类(不能被其他类继承) public 该类为公共类(可以从其他类中访问) 默认 该类为friendly类(只能被本包中的类使用)

注意:final修饰的类不可有子类。例如,java.lang.Math类就是一个final类,它不可以有子类

3.1.4 代码示例

public class Person {}

3.2 对象

3.2.1 对象

对象是具体的,实际的,代表一个事物。例如:车是一个类,汽车,自行车就是他的对象。
现实世界中,随处可见的一种事物就是对象,对象是事物存在的实体,如人类、书桌、计算机、高楼大厦等。人类解决问题的方式总是将复杂的事物简单化,于是就会思考这些对象都是由何种部分组成的。通常都会将对象划分为两部分,即动态部分与静态部分。静态部分,顾名思义,就是不能动的部分,,这部分被称为“属性”,任何对象都会具备其自身的属性,例如一个人,他包括高矮、胖瘦、性别、年龄等属性。然而具有这些属性的人会执行哪些动作也是一个值得探讨的部分,这个人可以哭泣、微笑、说话、行走,这些都是这个人具备的行为(动态部分),人类通过探讨对象的属性和观察对象的行为了解对象。
这里写图片描述

3.2.2 类和对象的关系

类是模板,对象是实例;类是抽象的,对象是具体的。类是建筑图纸,而对象是某个大楼
类与对象的关系图:
这里写图片描述

3.2.3 代码示例

public class Person {    public static void main(String[] args) {        new Person();    }}

3.3 构造函数

3.3.1 构造函数

构造函数/构造方法是一种特殊的函数。其主要功能是用来在创建对象时初始化对象, 即为对象成员变量赋初始值,总与new运算符一起使用在创建对象的语句中。构造函数与类名相同,可重载多个不同的构造函数。
构造函数的特点如下:

  • 构造函数没有返回值。
  • 构造函数的名称要与本类的名称相同

注意:在定义构造函数时,构造函数没有返回值,但这与普通的放回值的方法不同,普通没有返回值的方法使用public void test()这种形式进行定义,但构造函数并不需要void关键字进行修饰。
构造方法的定义语法格式如下

修饰符 <构造函数名称>(参数列表){    //构造方函数}

3.3.2 代码示例

代码示例1:动物类

//Animal类class Animal {    //默认构造函数的讲解    //定义构造方法    public Animal(){         System.out.prinltn("初始化实例对象");    }}

代码示例2:带有参数的构造函数

public class Animal{    //定义无参构造方法    public Animal(){          //使用this关键字调用有参构造方法        this("this调用有参构造方法");               System.out.println("无参构造方法");    }    //带有参数构造函数的讲解    public Animal(String name){        System.out.println("有参构造方法");       }    //这个是类的主方法,稍后会讲到    public static void main(String[] args) {        new Animal();    }}

输出结果:

有参构造方法无参构造方法

3.4 语句块

3.4.1 初始化块

语句块:用{}括起来的部分,我们称为语句块.也在类体中的语句块,我们称为初始化块!

3.4.2 案例1

  请参照案例:01

//初始化快案例public class Animal {    {        System.out.println("我是语句块,也叫初始化块!");    }    public Animal(){        System.out.println("构造函数,初始化对象");    }    public static void main(String[] args) {            new Animal();//注释掉执行,加上它执行,然后再new Animal();再执行....    }}

备注:解释初始化块执行的顺序,及应用场景。

初始化块使用分析:
- 当创建Java对象时,系统总是先调用该类里定义的初始化块;
- 如果一个类里定义了两个普通初始化块,则前面定义的初始化块先执行,后面定义的初始化块后执行。
- 初始化块虽然也是Java类里的一种成员,但它没有名字,也就没有标识,因此无法通过类、对象来调用初始化块;
- 初始化块只能在创建对象时自动执行而且在执行构造方法之前执行。

3.4.3 静态块

如果定义初始化块时使用了static修饰符,则这个初始化块就变成了静态初始化块,也被称为类初始化块。

  • 静态初始化块是类相关的,系统将在类初始化阶段执行静态初始化块,而不是在创建对象时才执行,因此静态初始块总是比普通初始化块先执行。
  • 静态初始块属于类的静态成员,用于对类属性执行初始化处理,不能对实例属性进行初始化处理。
  • 系统在类初始化阶段执行静态初始化时,不仅会执行本类的静态初始化块,还会一直上溯到Object类(如果它包含静态初始化块)。经过这个过程,才完成了对类的初始化过程。

3.4.4 案例2

请参照案例:02

//静态块案例public class Animal {    static{        System.out.println("我是静态块!!!!!!");    }    {        System.out.println("我是语句块,也叫初始化块!");    }    public Animal(){        System.out.println("构造函数,初始化对象");    }    public static void main(String[] args) {        new Animal();//注释掉执行,加上它执行,然后再new Animal();再执行....    }} 

3.5 成员属性

3.1.1 定义

在Java语言中对象的属性成为成员变量,也可以称为属性。为了了解成员变量,首先定义一个员工类。成员变量对应于类对象的属性,在Animal类中设置id(动物编号)、name(动物种类)

3.1.2 定义成员变量

  • 定义成员变量:[修饰符] 类型 成员变量名[=初始值];
  • 修饰符:[public|protected|private][static][final]
  • 成员变量名应是一个合法的标识符,并且应遵循编码惯例;
  • 初始值:定义变量还可以定义一个可选的初始值。

3.1.3代码示例

代码示例1:成员属性

//动物类public class Animal{    private int age;          //定义一个int型的成员变量    private String name;    //定义一个String型的成员变量    public static void main(String[] args) {        Animal a = new Animal();        a.age=1;        a.name="猫";       System.out.println(a.age+" "+a.name);    }}   

输出结果:

0  猫

代码示例2:成员属性

 /**  *   * @author chj  *  */public class Animal {   //定义一个int型的成员变量  年龄   private int age;     //定义一个String型的成员变量  名字   private String name;       //带有参数构造函数 :this介绍   public Animal(int age,String name) {       this.age=age;       this.name=name;    }   public static void main(String[] args) {    Animal a = new Animal(1,"猫");    System.out.println("动物名字:"+a.name+" 它的年龄:"+a.age);    } }

输出结果:

动物名字:猫 它的年龄:1

3.1.4 final修饰符

  1. final关键字可用于修饰类、变量和方法。

  2. final变量

    • final修饰变量时,表示该变量一旦获得了初始值之后就不可被改变,final既可修饰成员变量(包括类变量和实例变量),也可以修饰局部变量、形参。
      这里写图片描述
      代码示例1:final修饰符

      public class Animal {  //类变量  private static int age=99;    //常量  private final String SEX="男";  //静态的常量  private  final static String TAG="Animal";  //讲解各个初始化的问题  //讲解变量访问的问题

      }

  3. final修饰的类变量、实例变量能指定初始值的地方如下:

    • 类变量:静态初始化块或声明该属性时指定初始值。
    • 实例变量:非静态初始化块、声明该属性时或构造方法中指定初始值。

    注意:实例属性不能在静态初始化块中指定初始值,因为静态初始化块是静态成员,不可访问实例属性—非静态成员;类属性不能在普通初始化块中指定初始值,因为类属性在类初始化阶段已经被初始化了,普通初始化块不能对其重新赋值。

  4. final修饰局部变量

    • 可以在定义时指定默认值,则后面代码中不能再对该变量赋值。
    • 如果在定义时没有指定默认值,则可在后面代码中对该final变量赋初始值,但只能一次,不能重复赋值。
  5. final修饰基本类型和引用类型变量的区别
    这里写图片描述
    代码示例2 对象的属性值发生改变

    final Person p = new Person();p.name="chj";p.sex="男";  

3.6 方法

3.6.1 方法语法

在Java语言中使用方法对应于类对象的行为。定义方法的语法格式如下:

    修饰符 返回值类型 方法名([形式参数列表]){       //方法体      return 返回值;    }
  • 修饰符: [public|protected|private][static|][abstract|final]
  • 返回值类型:可以是Java语言的任何数据类型,如果声明了返回值类型,则方法体内必须有一个有效的return语句,该语句返回一个变量或表达式的值,变量或者表达式的类型必须与方法返回值类型匹配;如果一个方法没有返回值,则必须使用void来声明。
  • 方法名:命名规则与变量名的命名规则基本相同,但通常建议方法名以英文中的动词开头

3.6.2 方法的调用

对象名.方法名([实参表]); 如果是类方法 还可以通过 类名.方法名([实参表]);

  • 方法不能独立定义,只能在类体里定义。
  • 从逻辑意义上看,方法要么属于类,要么属于对象。因此,执行方法必须使用类或对象作为调用者。
  • 同一个类中的方法相互调用时,如果被调用方法是普通方法,则默认使用this 作为调用者,如果被调方法是静态方法,则默认使用类作为调用者。

    代码示例1

        public class Animal {       public static int age;       public String name;       public  void run(){         age=12;         name="";         this.sleep();         sleep();         sleep(1);         System.out.println("动物跑起来了@@@");       }       public void sleep(){          System.out.println("动物睡觉了@@@");       }       public void sleep(int hour){         System.out.println("动物睡了"+hour+"小时");       }      public static void main(String[] args) {          Animal animal = new Animal();          animal.run();          animal.sleep(10);      }    }  

    运行结果:

      动物睡觉了@@@  动物睡觉了@@@  动物睡了1小时  动物跑起来了@@@  动物睡了10小时

3.6.3 使用static修饰方法

静态方法可以直接通过类名调用,任何的实例也都可以调用。

例如为了方便方法的调用,Java API中的Math类中所有的方法都是静态的,而一般类内部的static方法也是方便其它类对该方法的调用。

静态方法是类内部的一类特殊方法,只有在需要时才将对应的方法声明成静态的,一个类内部的方法一般都是非静态的

请参照案例:03

    public class Animal {         public static int age;         public String name;         public static void run(){               age=12;        /*     name="";//语法错误               this.sleep();//语法错误               sleep();//语法错误       */      sleep(1);               System.out.println("动物跑起来了@@@");        }       public void sleep(){          System.out.println("动物睡觉了@@@");       }       public static void sleep(int hour){          System.out.println("动物睡了"+hour+"小时");       }       public static void main(String[] args) {         Animal.run();         Animal animal = new Animal();         animal.sleep(10);      }    }

运行结果:

      动物睡了1小时      动物跑起来了@@@      动物睡了10小时

注意:

  • 静态方法中不能使用this引用。
  • 静态方法只能处理静态属性、调用静态方法

3.6.4 方法的重载

方法重载是指在一个类中定义多个同名的方法,但要求每个方法具有不同的参数的类型或参数的个数
代码示例1

class Demo{   public void test(int a);     public void test(Strting a);     public void test(int a,int b);}

具体规范:

  1. 方法名一定要相同。
  2. 方法的参数列表必须不同,包括参数的类型或个数,以此区分不同的方法体。
    • 如果参数个数不同,就不管它的参数类型了!
    • 如果参数个数相同,那么参数的类型必须不同。
  3. 方法的返回类型、修饰符可以相同,也可不同。

代码示例2

Demo   cz =new Demo();cz.test(1);                   //调用test(int a);cz.test("传的参数");            //调用test(String a)cz.test(1,2);                 //调用test(int a,int b)

上面已经说了调用哪个方法了 而这个调用方法是程序按照你输入的参数来判断调用哪个方法的。

3.6.5 可变参数

  1. Java1.5增加了新特性:可变参数:适用于参数个数不确定,类型确定的情况,java把可变参数当做数组处理.

    • 只能出现在参数列表的最后,也就是说只能出现一次。
    • …位于变量类型和变量名之间,前后有无空格都可以
    • 调用可变参数的方法时,编译器为该可变参数隐含创建一个数组,在方法体中一数组的形式访问可变参数

    代码示例1

      /**   *    * @author chj   *   */public class Demo {public void print(String name,String... favs) {    System.out.print(name+"的爱好有:");    //遍历参数   for (int i = 0; i < favs.length; i++) {    //获取指定的参数值    System.out.print(favs[i]+"  ");   }   System.out.println();}public static void main(String[] args) {    //创建对象    Demo demo = new Demo();    //第一种调用方式    demo.print("于谦", "喝酒","抽烟","烫头");    //第二种调用方式    String favs[]={"喝酒","抽烟","烫头"};    demo.print("于谦", favs);    //第三种调用方式    demo.print("郭德刚");//调用的时候可以不传递可变参数的变量值  }}

    运行结果:

    于谦的爱好有:喝酒  抽烟  烫头  于谦的爱好有:喝酒  抽烟  烫头  郭德刚的爱好有:

    请参照案例04

    public class Demo {    /**    * 求和计算    *     * @param x    * @param arr    * @return    */    public int add(int... arr) {        // 声明计算结果        int sum = 0;        // 遍历arr可变参数        for (int i = 0; i < arr.length; i++) {            // 求和            sum += arr[i];        }        // 返回结果        return sum;    }    public static void main(String[] args) {        Demo demo = new Demo();        //求1到10的和        int sum = demo.add(1, 2,3,4,5,6,7,8,9,10);        System.out.println("sum="+sum);        int arr[]={1,2,3,4,5,6,7,8,9,10};        //求1到10的和        sum = demo.add(arr);        System.out.println("sum="+sum);        }    }
  2. 可变长参数的使用规则

    • 在调用方法的时候,如果能够和固定参数的方法匹配,也能够与可变长参数的方法匹配,则选择固定参数的方法
      示例代码2:

      /** *  * @author chj * */public class Demo {    /**     * 可变参数     * @param args     */    public void print(String... args) {        System.out.print("可变参数方法执行@@@@@@@@@@:");        for (int i = 0; i < args.length; i++) {            System.out.print(args[i]+"  ");        }    }    /**     * 固定参数     * @param test     */    public void print(String arg) {        System.out.println("固定参数方法执行@@@@@-"+arg);    }    public static void main(String[] args) {        Demo test = new Demo();        test.print("hello");        test.print("hello", "alexia");    }}
    • 如果要调用的方法可以和两个可变参数匹配,则出现错误
      示例代码3:

      /** *  * @author chj * */public class Demo {    /**     * 可变参数     * @param args     */    public void print(String... args) {        System.out.print("可变参数方法执行@@@@@@@@@@:");        for (int i = 0; i < args.length; i++) {            System.out.print(args[i]+"  ");        }    }    /**     * 固定参数     * @param test     */    public void print(String arg,String ...favs) {        System.out.println("固定参数方法执行@@@@@-"+arg);    }    public static void main(String[] args) {        Demo test = new Demo();        test.print("hello"); //语法错误        test.print("hello", "alexia");//语法错误    }}
    • 一个方法只能有一个可变长参数,并且这个可变长参数必须是该方法的最后一个参数

3.6.6 方法的参数传递

  • 基本类型的变量作方法参数;值传递:方法调用时,实际参数把它的值传递给对应的形式参数,方法执行中形式参数值的改变不影响实际参.

    * 示例代码4*:两个数值的交换

        public class Demo {        public static void change(int i, int j) {            int temp = i;            i = j;            j = temp;        }        public static void main(String[] args) {            int a = 3;            int b = 4;            change(a, b);            System.out.println("a=" + a);            System.out.println("b=" + b);        }    }

运行结果:

    a=3    b=4
  • 引用类型的变量作方法参数;引用传递:也称为传地址。方法调用时,实际参数的引用(地址,而不是参数的值)被传递给方法中相对应的形式参数,在方法执行中,对形式参数的操作实际上就是对实际参数的操作,方法执行中形式参数值的改变将会影响实际参数的值。

示例代码5

        public class Demo {            public static void change(int[] counts) {                counts[0] = 6;                System.out.println("改变的值@@@@@"+counts[0]);            }            public static void main(String[] args) {                int[] count = { 1, 2, 3, 4, 5 };                System.out.println("改变前@@@@@"+count[0]);                change(count);                System.out.println("改变后@@@@@"+count[0]);            }        }

运行结果:

    改变前@@@@@1    改变的值@@@@@6    改变后@@@@@6

示例代码6

            public class Demo {                private int x;                private int y;                public void change(Demo demo){                    //记录变量                    int temp=0;                    //记录x值                    temp=demo.x;                    //把y值复制给x                    x=demo.y;                    //再把记录的x值 赋值给y                    demo.y=temp;                }                public static void main(String[] args) {                    //定义对象                    Demo demo = new Demo();                    //对象赋值                    demo.x=3;                    demo.y=4;                    //对象改变值                    demo.change(demo);                    //输出对象的属性值                    System.out.println(demo.x+"@@"+demo.y);                }            }

运行结果:

            4@@3

作业思考一下代码输出结果:

        public class Demo {            int x = 3;            public static void show(Demo d) {                d.x = 4;            }            public static void main(String[] args) {                Demo d = new Demo();                d.x = 9;                System.out.println("x="+d.x);                show(d);                System.out.println("x=" + d.x);            }        }  

3.7 类的隐藏和封装

封装(Encapsulation)是面向对象三大特征之一(封装、继承、多态),它指的是将对象的状态信息隐藏在内部,不允许外部程序直接访问对象内部信息,而是通过该类所提供的方法来实现对内部信息的操作和访问。

对一个类或对象实现良好的封装,可以实现以下目的:

  • 隐藏类的实现细节。
  • 让使用者只能通过事先预定的方法访问数据,从而可以在该方法里加入控制逻辑,限制对属性不合理访
    问。
  • 可进行数据检查,从而有利于保证对象信息的完整性。
  • 便于修改,提高代码的可维护性。

为了实现良好的封装,需要从两个方面考虑:

  • 将对象的属性和实现细节隐藏起来,不允许外部直接访问。
  • 把方法暴露出来,让方法来操作或访问这些属性。

这里写图片描述

访问控制符的权限范围介绍
这里写图片描述

思考以下示例能否被访问:

public class Dog {    private String name;    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }}

总结
访问控制符的使用总结:

  • 类中绝大部分属性应该使用private修饰,除了一些static修饰的、类似全局变量的属性,才考虑使用public修饰。
  • 有些方法只是用于辅助实现该类的其他方法,这些方法被称为工具方法,也应用private修饰。
  • 如果某个类主要用作其他类的父类,该类里包含的大部分方法可能仅希望被其子类重写,而不想被外界直接调用,则应该使用protected修饰这些方法。
  • 希望暴露出来给其他类自由调用的方法使用public修饰。
  • 顶级类通常都希望被其他类自由使用,所以大部分顶级类都使用public修饰。

5 总结

  • 了解类的基本概念及格式
  • 了解类和对象的关系
  • 了解构造函数的用法及其作用
  • 了解区分哪些是语句块
  • 了解成员属性的几种情况
  • 了解方法中成员方法、静态方法的使用
  • 了解类的隐藏与封装是怎样实现的

6 预习任务

  • 继承的特点,重写父类中的方法,父类实例的super引用
  • 调用父类的构造器,子类对象和父类对象的转换
  • final修饰的类、方法、属性
  • super与this的区别
  • 抽象类

以上都是个人整理资料部分,有问题欢迎大家留言!如需转载,请注明出处!

1 0
原创粉丝点击