面向对象基础(一)——三大特性、类与对象、封装private、构造方法

java中Scanner类nextLine()和next()的区别和使用方法:
在这里插入图片描述

import java.util.Scanner;
public class Main{
    public static void main(String[] args) {
        String s1,s2;
        Scanner sc=new Scanner(System.in);
        System.out.print("请输入第一个字符串:");
        s1=sc.nextLine();
        System.out.print("请输入第二个字符串:");
        s2=sc.next();
        System.out.println("输入的字符串是:"+s1+" "+s2);
    }
}

在这里插入图片描述

1.对于面向对象的程序设计有封装性、继承性、多态性3个主要特性。
(1)封装性
①一是指把对象的属性和行为看成一个密不可分的整体,将这两者“封装”在一个不可分割的独立单位(即对象)中;
②另一层含义指“信息隐蔽”,把不需要让外界知道的信息隐藏起来,并保证外界不能任意更改其内部的属性值,也不能任意调动其内部的功能方法。

(2)继承性
首先拥有反映事物一般特性的类,然后在其基础上派生出反映特殊事物的类。如已有汽车的类,该类中描述了汽车的普遍属性和行为,进一步再产生轿车的类,轿车的类是继承于汽车类,轿车类不但拥有汽车类的全部属性和行为,还增加轿车特有的属性和行为。
被继承的类称为父类或超类,而经继承产生的类称为子类或派生类。根据继承机制,派生类继承超类的所有成员,并相应地增加了自己的一些新的成员。
面向对象程序设计中的继承机制大大增强了程序代码的可复用性,提高了软件的开发效率,降低了程序产生错误的可能性,也为程序的修改扩充提供了便利。
若一个子类只允许继承一个父类, 则称为单继承;若允许继承多个父类,则称为多继承。目前许多面向对象程序设计语言不支持多继承。而Java语言通过接口(interface)的方式来弥补由于Java不支持多继承而带来的子类不能享用多个父类的成员的缺点。
(3)多态性
多态是允许程序中出现重名现象。Java语言中含有方法重载与对象多态两种形式的多态。
方法重载:在一个类中,允许多个方法使用同一个名字,但方法的参数不同,完成的功能也不同。
对象多态:子类对象可以与父类对象进行相互转换,而且根据其使用的子类的不同,完成的功能也不同。
多态的特性使程序的抽象程度和简捷程度更高,有助于程序设计人员对程序的分组协同开发。

例:

public class Employee {

    String name;
    int age;
    double salary;

    public Employee(String name){
        this.name = name;
    }

    public void empAge(int empAge){
        age = empAge;
    }

    public void empSalary(double empSalary){
        salary = empSalary;
    }
    public void printEmployee(){
        System.out.println(name);
        System.out.println(age);
        System.out.println(salary);
    }
}
public class EmployeeTest {

    public static void main(String[] args) {

        Employee employee = new Employee("zcy");

        employee.empAge(21);
        employee.empSalary(8888);
        employee.printEmployee();
    }
}
程序输出:
zcy
21
8888.0

2.类与对象的关系
在面向对象中,类和对象是最基本、最重要的组成单元。实际上是表示一个客观世界某类群体的一些基本特征抽象。对象就是表示一个个具体的东西。
例如,在现实生活中,人就可以表示为一个类,因为人本身属于一种广义的概念,并不是一个具体的。而某一个具体的人,就可以称为对象,可以通过各种信息完整地描述这个具体的人,如这个人的姓名、年龄、性别等信息,这些信息在面向对象的概念中就称为属性;当然人是可以吃饭、睡觉的,这些人的行为在类中就称为方法。也就是说如果要使用一个类,就一定有产生对象,每个对象之间是靠各个属性的不同来进行区分的,而每个对象所具备的操作就是类中规定好的方法。类与对象的关系如图所示:
在这里插入图片描述
(1)类的定义
类是由属性和方法组成的。属性中定义类一个个的具体信息,实际上一个属性就是一个变量,而方法是一些操作的行为,但是在程序设计中,定义类也是要按照具体的语法要求完成的,类的定义语法如下:
在这里插入图片描述
在类中的属性实际上也就是相当于一个个变量,有时也称这些为Field (成员)。

:定义Person类
c1ass Person{ 
     String name;           //声明姓名属性
     int age;               //声明年龄属性
     public void tell(){    //取得信息的方法
         System.out.println("姓名: " + name + ",年龄:+ age);
     }
 }
 在上面程序中,Person类定义了name和age两个属性,分别表示人的姓名和年龄,然
后定义了一个tell方法,此方法的功能就是打印这两个属性的内容。

Person的类图:
在这里插入图片描述
第1层表示类的名称,类的名称要求开头首字母大写。
第2层表示属性的定义,按照“访问权限属性名称:属性类型”的格式定义,在本类中因为声明属性处没有写任何的访问权限,所以前面暂时不加任何的符号。
第3层表示类中方法的定义,按照“访问权限 方法名称():方法返回值”的格式定义,在本类中方法的声明处加上了public(此为访问权限,表示任何地方都可以访问),所以使用“+”表示。另外,如果方法中有传递的参数,则方法定义格式为“访问权限 方法名称(参数名称:参数类型,参数名称:参数类型,…):方法返回值”。

(2)对象的创建及使用
在上面已经创建好了一个Person类,要想使用一个类则必须有对象。

对象的创建格式:
类名 对象名称 = null;         //声明对象
对象名称 = new 类名();       //实例化对象
用以上格式产生对象分为声明对象和实例化对象两步。
当然也可以直接通过以下方式一步完成:
类名 对象名称 = new 类名();
例:创建对象
c1ass Person{ 
     String name;           //声明姓名属性
     int age;               //声明年龄属性
     public void tell(){    //取得信息的方法
         System.out.println("姓名: " + name + ",年龄:+ age);
     }
 }
public class ClassDemo01 {
    public static void main(String args[]){
         Person per = new Person();   //创建并实例化对象
    }
}
以上程序在主方法中实例化了一个Person对象,对象名称为per。

与数组开辟空间一样,对象的实例化也是要划分堆、栈空间的,具体的内存分配如图所示:
在这里插入图片描述
从图可以发现,所有的对象名称都在栈内存中保存,而对象的具体内容则保存在对应的堆内存之中,必须使用new关键字才能开辟堆内存空间,此时,因为per对象刚刚被实例化完,所以对象中的属性内容都是默认值,字符串的默认值为null,整数的默认值为0。

访问对象中的属性或方法的格式:
访问属性:对象名称.属性名
访问方法:对象名称.方法名():为对象的属性设置内容,同时调用tell方法把内容输出
class Person {
     String name;    //声明姓名属性
     int age;        //声明年龄属性
     public void tell(){     //取得信息的方法
          System.out.println("姓名:"+ name + ",年龄:"+ age);
     }
}
public class ClassDemo02{
    public static void main (String args[]){
         Person per = null;
         per.name = "张三";      //为name属性赋值
         per.age = 30;          //为age属性赋值
         per.tell();            //调用类中的方法
    }
}

程序运行结果:
姓名:张三,年龄: 30

上面程序为属性赋值,并通过类中提供的方法把内容直接输出,属性赋值完之后的内存如图所示:
在这里插入图片描述
在这里插入图片描述
(3)创建多个对象

:创建两个对象
class Person{
      String name;             //声明姓名属性
      int age;                 //声明年龄属性
      public void tell(){      //取得信息的方法
         System.out.println("姓名:"+ name + ", 年龄: " + age);
      }
}
public class ClassDemo03{
      public static void main(String args[]){
           Person per1 = null;     //声明per1对象
           Person per2 = null;    //声明per2对象
           per1 = new Person();   //实例化per1对象
           per2 = new Person();   //实例化per2对象
           per1.name = "张三";    //设置per1对象的name属性内容
           per1.age = 30;         //设置per1对象的age属性内容
           per2.name = "李四";    //设置per2对象的name属性内容
           per2.age = 33;        //设置per2对象的age属性内容
           System.out.print ("per1对象中的内容--> ");
           per1.tell();          //per1调用方法
           System.out.print ("per2对象中的内容--> ");
           per2.tell();          //per2调用方法
      }
  }
程序运行结果:
per1对象中的内容-->姓名:张三, 年龄: 30
per2对象中的内容-->姓名:李四, 年龄: 33

由程序的运行结果可以发现,程序分别实例化了两个Person对象,那么也就意味着per1和per2对象分别指向各自的堆内存空间,如图所示:
在这里插入图片描述
3.封装性
封装性是面向对象的第一大特性,所谓的封装性就是指对外部不可见。

使用封装性格式:
为属性封装: private 属性类型 属性名称;
为方法封装: private 方法返回值 方法名称(参数列表) { }:为程序加上封装属性
c1ass Person{
     private String name;       //声明姓名属性
     private int age;           //声明年龄属性
     pub1ic void tell(){        //取得信息的方法
         System.out.println("姓名: " + name + ",年龄: " + age);
     }
}
public class EncDemo01 {
     public static void main(String args[]){
         Person per = new Person();
         per.name = "张三";     //错误,无法访问封装属性
         per.age = -30;        //错误,无法访问封装属性
         per.tell();
     }
}

本程序就是这一个小小的关键字private,使程序连编译都无法通过,而所提示的错误为“属性(name、age)为私有的”,所以不能由对象直接进行访问,这样就可以保证对象无法直接去访问类中的属性。
为了解决属性必须封装且又必须访问的矛盾,在Java开发中对于私有属性的访问有了以下的明确定义:“只要是被封装的属性,则必须通过setter和getter方法设置和取得”。

c1ass Person{
     private String name;       //声明姓名属性
     private int age;           //声明年龄属性
     public void tell(){        //取得信息的方法.
         System.out.println("姓名: " + name + ",年龄: " + age);
     }
     public String getName(){         //取得姓名
        return name;
     }
     public void setName(String n){   //设置姓名
        name = n;
     }
     public int getAge(){             //取得年龄
        return age;
     }
     public void setAge(int a){       //设置年龄
        if (a >= 0 && a < 150){       //在此处加上验证代码
           age = a;
        }
     }
}
public class EncDemo02{
     public static void main(String args[]){
         Person per = new Person();    //声明并实例化对象
         per.setName ("张三");         //调用setter设置姓名
         per.setAge(-30);             //调用setter设置年龄
         per.tell();
     }
}

程序运行结果:
姓名:张三, 年龄: 0
从程序运行结果可以发现,因为程序中在setter方法处加入了验证代码,所以如果
的年龄数值不正确,则不会把值赋给age属性,所以程序运行结果处出现的年龄为0

关于private的补充说明。
(1)在以后的开发中读者一定要明确,类中全部属性都必须封装,封装之后的属性必须通过setter和getter 进行访问。
(2)面向对象的封装性本身并不是单单指private关键字,用private声明的属性或方法只能在其类的内部被调用,而不能在类的外部被调用。
(3)正常情况下,类中的方法直接写上方法名称就可以完成本类中的方法调用,如果在此时非要强调是本类中的方法,也可以在调用时按“this.方法名称()”的形式编写:

public void tell(){
     System.out.println("姓名:" + this.getName() +",年龄:" + this.getAge());
}

在代码中是否使用this明确地表示当前类中的方法并没有严格的要求,但是建议编写代码时最好采用"this.方法名称()”的形式,这样会比较标准一些,在查错时也会更加方便。

程序中的属性进行封装后,在使用类图表示封装属性时按照如下格式:
-属性名称:数据类型    (-表示private

上面程序的类图表示:
在这里插入图片描述
4.构造方法
从前面所讲解的代码可以发现,实例化一个类的对象后,如果要为这个对象中的属性赋值,则必须用setter方法,那么有没有一种简单的方法,可以在对象实例化时就直接把对象的值赋给属性呢?此时,就可以通过构造方法完成这样的操作,在面向对象程序中构造方法的主要作用是为类中的属性初始化
回顾对象的产生格式,例如现在要产生一个类的对象,则必须使用以下格式的代码:

类名称 对象名称= new 类名称();

在程序中只要有“()”就表示调用了方法,那么这个方法实际上就是表示要调用构造方法,构造方法可视为一种特殊的方法,其语法格式如下:
在这里插入图片描述
构造方法的名称必须与类名称一致。
构造方法的声明处不能有任何返回值类型的声明。
不能在构造方法中使用return返回一个值。

范例:声明一个构造方法
class Person {
    public Person(){     //声明构造方法
        System.out.println ("一个新的Person对象产生。");
    }
}
public class ConsDemo01{
    public static void main(String args[]){
        System.out.println("声明对象: Person per = null;");
        Person per = null;     //声明对象时不调用构造方法
        System.out.println("实例化对象: per = new Person();");
        per = new Person();    //实例化对象时调用构造方法
    }
}

程序运行结果如下:
在这里插入图片描述
在类中定义一个Person类的构造方法,当调用new关键字实例化对象时才会调用构造方法
只要是类就必须存在构造方法,在Java中如果一个类中没有明确地声明一个构造方法,则在编译时会直接生成一个无参数的、什么都不做的构造方法,也就是说,如果以上的Person类中没有明确地声明构造方法,实际上编译之后的类就会为用户自动加上以下形式的构造方法:

class Person{
     public Person() { }
}

以上程序的类图表示:
在这里插入图片描述

:通过构造方法为属性赋值
c1ass Person{
     private String name;       //声明姓名属性
     private int age;           //声明年龄属性
     public Person(String name, int age){   //定义构造方法为属性初始化
          this.setName(name);   //为name属性赋值
          this.setAge(age);     //为age属性赋值
     }
     public void tell(){        //取得信息的方法
         System.out.println("姓名: " + name + ",年龄: " + age);
     }
     public String getName(){         //取得姓名
        return name;
     }
     public void setName(String n){   //设置姓名
        name = n;
     }
     public int getAge(){             //取得年龄
        return age;
     }
     public void setAge(int a){       //设置年龄
        if (a >= 0 && a < 150){          //在此处加上验证代码
           age = a;
        }
     }
}
public class ConsDemo02{
     public static void main(String args[]){
        Person per = new Person("张三",30); //调用构造方法,传递两个参数
        per.tell();                         //输出信息
     }
}

程序运行结果如下:
姓名: 张三,年龄: 30

以上程序就是直接通过构造方法进行赋值,可以发现,这样赋值比对象实例化之后再
单独调用setter方法更方便。

在一个类中如果已经明确地声明了一个构造方法,那么程序在编译时将不会再生成默认的构造方法,即一个类中应保证至少有一个构造方法。
与普通方法一样,构造方法也是可以重载的,只要每个构造方法的参数类型或参数个数不同,即可实现重载。

:构造方法重载
c1ass Person{
     private String name;       //声明姓名属性
     private int age;           //声明年龄属性
     public Person(){}
     public Person(String name){   //定义构造,为name属性赋值
       this.setName(name); 
     }
     public Person(String name, int age){   //定义构造方法为属性初始化
          this.setName(name);   //为name属性赋值
          this.setAge(age);     //为age属性赋值
     }
     public void tell(){        //取得信息的方法
         System.out.println("姓名: " + name + ",年龄: " + age);
     }
     public String getName(){         //取得姓名
        return name;
     }
     public void setName(String n){   //设置姓名
        name = n;
     }
     public int getAge(){             //取得年龄
        return age;
     }
     public void setAge(int a){       //设置年龄
        if (a >= 0 && a < 150){          //在此处加上验证代码
           age = a;
        }
     }
}
public class ConsDemo02{
     public static void main(String args[]){
        Person per = new Person("张三");     //调用有一个参数的构造
        per.tell();                         //输出信息
     }
}

程序运行结果如下:
姓名: 张三,年龄: 0

以上类的构造方法被重载了3次,在主方法调用的是只有一个参数的
构造方法(只设置姓名),因为没有设置年龄,所以年龄为默认值0

实例分析
定义并测试一个名为Student的类,包括的属性有“学号”、“姓名”以及3门课程“数学”、"英语”和“计算机”的成绩,包括的方法有计算3门课程的“总分”、“平均分”、“最高分”及“最低分”。
(1)本类中的属性及类型,如表所示:
在这里插入图片描述
(2)定义出需要的方法(普通方法、构造方法)
在本例中设计两个构造方法,一个是无参的构造方法,另外一个构造方法可以为5个属性进行赋值,如表所示:
在这里插入图片描述
本例类图如下:
在这里插入图片描述

:实现代码
class Student{                       //定义学生类
    private String stuno;            //学生编号
    private String name;             //学生姓名
    private float math;              //数学成绩
    private float english;           //英语成绩
    private float computer;          //计算机成绩
    public Student() {}              //定义无参构造
    public Student(String stuno, String name, float math, float english,float computer){         //定义有5个参数的构造方法,为类中的属性初始化
        this.setStuno(stuno);        //设置编号
        this.setName(name);          //设置姓名
        this.setMath(math);          //设置数学成绩
        this.setEnglish(english);    //设置英语成绩
        this.setComputer(computer);  //设置计算机成绩
    }
    public void setStuno(String s){   //设置编号
          stuno = s;
    }
    public void setName(String n){    //设置姓名
          name = n;
    }
    public void setMath(float m){     //设置数学成绩
          math = m;
    }
    public void setEnglish(float e){  //设置英语成绩
          english = e;
    }
    public void setComputer(float c){ //设置计算机成绩
          computer = c;
    }
    public String getStuno(){         //取得编号
          return stuno;
    }
    public String getName(){          //取得姓名
          return name;
     }
     public float getMath(){         //取得数学成绩
          return math;
     }
     public float getEnglish(){      //取得英语成绩
          return english;
     }
     public float getComputer(){     //取得计算机成绩
          return computer;
     }
     public float sum(){            //计算总分
          return math + english + computer;
     }
     public float avg(){           //计算平均分
          return this.sum() / 3;   //总分除以3
     }
     public float max(){          //最高成绩
          float max = math; 
          max = max > computer ? max : computer;   //使用三目运算符
          max = max > english ? max : english;     //使用三目运算符
          return max ;
     }
     public float min(){        //最低成绩
          float min = math;
          min = min < computer ? min : computer;   //使用三月运算符
          min = min < english ? min : english;     //使用三目运算符
          return min;
     }
}

编写测试类,测试以上代码:
public class ExampleDemo{
     public static void main(String args[]){
         Student stu = null;         //声明对象
         //实例化Student对象,并通过构造方法赋值
         stu = new Student("001", "小明",95.0f, 89.0f, 96.0f);
         System.out.println("学生编号: " + stu.getStuno());
         System.out.println("学生姓名: " + stu.getName());
         System.out.println("数学成绩: " + stu.getMath());
         System.out.println("英语成绩: " + stu.getEnglish());
         System.out.println("计算机成绩: " + stu .getComputer());
         System.out.println("总分: " + stu.sum());
         System.out.println("最高分: " + stu.max());
         System.out.println("最低分: " + stu.min());
      }
}

程序运行结果如下:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值