面向对象 (成员变量、局部变量、封装)

软件的开发方式

面向过程

  • 站在过程的角度思考问题,强调的是我该怎么去做。即功能的执行的过程,即先干什么,后干什么

  • 面向过程的缺点

    • 面向过程,系统软件的适应性差,可拓展性差,维护性低

面向对象

  • 面向对象编程,是一种通过对象的方式 把现实世界映射到计算机模型中的一种编程方法.

  • 站在对象的角度思考问题,将多个功能合理的放到不同的对象中,强调的是我应该让谁来做。

  • 面向对象的三大特征

    • 封装(encapsulation)
    • 继承(inheritance)
    • 多态(polymorphism)
  • 面向对象中最小的程序单元是类,必须先存在类的定义,再有对象,从而具备某种功能的实体。

  • 在面向对象的世界里。如果你想做什么事情,首先找对象。

面向过程和面向对象的区别?

  • 面向过程是站在过程的角度上思考,注重的是实现方法的步骤,过程。

    面向对象是站在对象的角度上思考的,注重的是强调做某件事的个体、对象。

  • 过程是由一个个步骤组成的,然后将这些步骤转换成为函数。

    对象是由字段(成员变量、实例变量)和方法(成员方法)组成的。

  • 面向过程:性能较好,常常使用在单片机、嵌入式开发 可是 系统软件的适应性差,可拓展性差、维护性低

    面向对象:易于维护、易于复用,易于扩展,由于面向对象有封装、继承、多态的特性,可以设计出低耦合的系统,使系统更加灵活,更加易于维护。

什么是抽象

  • 所谓抽象,从特定的角度出发,从已经存在的多个事物中抽取我们所关注的特性、行为、从而产生一个新的事物的思维过程,是一种从复杂到简洁的思维方式。
    • 还可以这样去理解:所谓抽象,就是将现实世界的事物,提取公共的特征和行为,也即提取其像的部分,提取到计算机中的过程,假设我们要做一个宠物管理系统,那么我们需要对宠物进行抽象 -> 提取宠物的公共特征和行为-> 提取到计算机中,-> 计算机怎么描述这个抽象(定义一个类)->通过类创建对象。

成员变量和局部变量

变量的分类

  • 根据变量定义的位置的不同

    • 成员变量:直接定义在类中,方法外名。又称之为字段,不要称之为属性。

    • 局部变量:除了成员变量,其他都是局部变量 ,具体在三个地方

      • 方法内
      • 方法的形参
      • 代码块中(一对花括号)
    • Demo01Var.java

      public class Demo01Var {
          // 成员变量(字段):在类的内部 在方法的外部 作为类的成员 不能叫属性
          int count = 10;
      
          public static void add(int num1,int num2){
              // 局部变量 方法里面定义的变量 形参
              int r = num1 + num2;
      
              // 代码块 用{}起来的内容成为代码块 可以形成作用域
              {
                  int count = 20;
                  System.out.println(count);
                  System.out.println(r);
              }
              // System.out.println(count);
      
              /**
               * 总结:
               * 1. {}成为代码块 可以形成作用域
               * 2. 作用域可以嵌套 内层作用域可以访问外层的作用域的变量,外层的作用域不能访问内层的作用域的变量
               */
          }
          public static void main(String[] args) {
              add(10,20);
          }
      }
      
      

变量从初始值

  • 成员变量:默认是有初始值的,不同类型的初始值
  • 局部变量:没有初始值,需要先声明,然后初始化,才能使用

变量的作用域

  • 成员变量:在所有定义的类中都有效
  • 局部变量:从开始定义的位置开始,只能在自己所在的花括号内有效

变量的生命周期

  • 成员变量:存储在堆内存中,随着对象的销毁而销毁 (main方法结束)
  • 局部变量:存储在栈内存中,随着所定义的方法的调用结束而销毁。
    • 局部变量存储在方法中,每次调用方法,都会在在空间开辟一块内存空间 – 栈帧,方法调用结束,栈帧被销毁,内存中的存储的变量数据也销毁了。

类和对象的关系

  • 类:是对某一类事物的抽象描述(状态和行为)
    • 类是一组具有相同特征和行为的对象的抽象描述(集合),类是一个群体概念
  • 对象:表示对现实生活该类事物的个体,也称之为实例。
    • 对象是类这个群体中的一个唯一的、独立的个体,对象是个体概念,这个个体在程序中成为实体或者实例。
  • 类可以看作是对象的数据类型。

类的定义

  • 使用成员变量(字段、实例变量)来表示状态。
  • 使用成员方法(方法)来表示行为。
public class 类名{ //可编写0到N个成员变量 
    [修饰符] 数据类型 变量名1; 
    [修饰符] 数据类型 变量名2; 
    
    //可编写0到N个成员方法
    [修饰符] 返回值类型 方法名称(参数){ 
        //方法体   
   }   
}

​ 在描述对象的类中,不需要定义main方法,专门在测试的类中定义main方法。

在面向对象设计中,描述对象的类和测试类分开来编写。

对象的操作

基本操作

  • 创建对象
类名 对象变量名 = new 类名();
  • 通过对象调用字段
对象名.字段名 =;
  • 获取字段的值
数据类型 变量名 = 对象名.字段名;
  • 对象调用方法
对象变量名.方法(参数);
  • 定义一个Student类

    public class Student {
        String sid;
        String name;
        int age;
        /**
         * 成员方法 => 类的行为
         * 一个成员方法
         * @param aClass
         */
        public void learn(String aClass) {
            System.out.println(name + "正在学习" + aClass);
        }
    
        public void sayHi() {
            System.out.println(name + "同学,正在Say Hi.");
        }
    
    }
    
  • 调用Student类

    public class Demo01Test {
        public static void main(String[] args) {
            // 1> 类是一种数据类型
            // [1] 可以用于声明变量
            Student s1  = null;
            // [2] 为变量s1申请堆内存空降
            s1 = new Student();
    
            // 合二为一
            // new了一个s1对象,s1也称之为student的实例,又称为student的一个对象
            Student s2 = new Student();
            System.out.println(s2);
    
            Student s3 = new Student();
            System.out.println(s3);
    
            // s1 ,s2都属于Student类的对象,但是他们这个是独立的且是唯一的
            // s1,s2 都属于同一类(Student) s1和s2都具有Student中描述的特性(状态)和行为(功能)
            s1.age = 10;
            s1.name = "小明";
            s1.learn("Java");
        }
    }
    

构造器

  • 构造器的语法
// 无参构造方法
[修饰符] 类名(){
    
}
// 有参构造方法
[修饰符] 类名(参数){
    字段1 = 参数1;
}

注意:

构造器名字和类的名字要高度一致

构造器有两种创建的方法,一个是有参数的构造器,一个是无参数的构造器,这两种方法构成了重载

不能定义返回值类型

不能使用return语句

public class User {

    String uid;
    String name;
    int age;
    String info;
    /**
     * 无参构造方法一定用于对实例进行赋初始值/默认值
     */
    public User() {
        age = 18;
        info = "这个人很懒,什么也没有留下";
    }
    /**
     * 如果想在构建对象的时候就给对象赋值,此时我们可以考虑使用有参构造
     */
    public User(String aUid, String aName, int Age, String aInfo) {
        uid = aUid;
        name = aName;
        age = Age;
        info = aInfo;
    }
    /**
     * 如果一个类,开发者没有显示的定义任何构造方法,jvm会默认分配无参构造
     * 如果开发者定义了有参或者无参,jvm都不会再分配无参构造
     * 好的开发者;当定义了有参构造的时候,一定习惯的把无参构造给加上,哪怕无参构造什么也不做
     */
    public void showInfo() {
        System.out.println("姓名:\t" + name);
        System.out.println("年龄:\t" + age);
        System.out.println("编号:\t" + uid);
        System.out.println("简介:\t" + info);
    }
}
构造方法
  • 创建实例的时候,我们经常需要同时初始化这个实例的字段
Person ming = new Person();
ming.setName("小明");
ming.setAge(12);

初始化对象实例需要3行,而且,如果忘记调用setName() 或者 setAge(),这个实例的内部的状态就是不正确的.

  • 在创建对象实例的时候就把内部字段全部初始化为合适的值?

  • 这时 , 我们需要构造方法

  • 创建实例的时候,实际上是通过构造方法来初始化实例的,我们先定义一个构造方法,能在创建Person实例的时候,一次性传入name和age,完成初始化:

class Person{
    
    private String name;
    private int age;
    
    public Person(String name,int age){
        this.name = name;
        this.age = age;
    }
    
    public String getName(){
        return this.name;
    }
    
    public int getAge(){
        return this.age;
    }
    
}
  • 构造方法没有返回值(和普通方法相比) 调用构造方法,必须使用new操作符.
  • 构造方法的参数没有限制,在方法内部,也可以编写任意语句
  • 构造方法的名字就是类名
默认构造方法
  • 一个类如果没有定义任何构造方法,编译器会自动帮我们生成一个默认构造方法,他没有参数,也没有执行语句
class Person{
    
    public Person(){
        
    }
    
}
  • 如果我们自定义了一个构造方法,那么,编译器就不再自动创建默认的构造方法了

构造器总结

构造器(或构造方法、constructor)的使用

  • construct:建设、建造。 construction:CCB constructor:建设者

一、构造器的作用:

  • 1.创建对象
  • 2.初始化对象的信息

二、说明:

  • 1.如果没有显式的定义类的构造器的话,则系统默认提供一个空参的构造器
  • 2.定义构造器的格式:权限修饰符 类名(形参列表){}
  • 3.一个类中定义的多个构造器,彼此构成重载
  • 4.一旦我们显式的定义了类的构造器之后,系统就不再提供默认的空参构造器
  • 5.一个类中,至少会有一个构造器。

练习

请给Person类增加(String,int)的构造方法

class Person{
    
    private String name;
    private int age;
    
    public Person(String name, int age){
        this.name = name;
        this.age = age;
    }
    
    public String getName(){
        return name;
    }
    
    public int getAge(){
        return age;
    }
    
    
}

为什么存在对象

  • 为什么存在对象?
  • 对象是数据的载体,开发本质上就是把数据组存入计算机中,需要一种更加复杂的数据类型,而且这个复杂的数据类型一定要是自定义的
  • 进而,软件开发就是把现实中的数据存储到计算机中,必须把共同的特性和行为抽象到计算机中作为类而存在,类又可以创建对象
  • 软件开发数据的展示是,一定要找对象 => 无论你做什么都需要找对象 => 在你眼里一切皆需要对象 => 你眼里只有对象 => 这就是面向对象 => 面向什么就可以看到什么?

封装思想

  • 一个class可以包含多个字段(field),例如我们给person类定义两个field
class Person{
    
    public String name;
    public int age;
    
}
  • 但是,直接把field用public暴露给外部,可能会破坏封装性,比如
Person p = new Person();
p.name = "小明";
p.age = -99;
  • 直接操作field 容易造成逻辑混乱. 为了避免外部代码直接去访问field,我们可以用private修饰field,拒绝外部访问:
class Person{
    private String name;
    private int age;
}
  • 封装是面向对象的三大特征之一,
    • 将对象和字段存放在一个独立的模块中(类)
    • 隐藏信息,尽可能隐藏对象的数据和功能的实现细节
  • 好处
    • 保证数据的安全性,防止调用者随意修改数据
    • 提高组件的重用性,把公用功能放到一个类中,谁需要该功能,直接调用即可。
private方法
  • private方法不允许外部进行调用
  • 定义private方法的理由是内部方法可以调用private方法的
class Person{
    
    private String name;
    private int birth;
    
    public void setBirth(int birth){
        this.birth = birth;
    }
    
    public int getAge(){
        // 调用private方法
        return calcAge(2019);
    }
    
    private int calcAge(int currentYear){
        return currentYeat - this.birth;
    }
    
}
  • 上述代码中 calaAge()是一个private方法,外部代码无法调用,但是,内部方法**getAge()**可以进行调用
  • 这个Person类只是定义了birth字段,没有定义age字段,获取age的时候,通过方法getAge()返回的是一个实时计算的值,并非存储在某个字段中的值,这说明方法可以封装一个类的对外的接口,调用方不需要知道,关心person实例在内部到底有没有age字段.
this变量
  • 在方法内部,可以使用一个隐含的变量this,它始终指向当前的实例.因此,通过this.field就可以访问当前实例的字段,如果没有命名冲突,可以省略this
class Person{
    
    private String name;
    public String getName(){
        return name; // 相当于this.name
    }
    
}
  • 但是,如果有局部变量和字段重名,那么局部变量的优先级更高,就必须加上this:
class Person{
    
    private String name;
    
    public void setName(String name){
        // 前面的this必不可少,少了就变成局部变量name了
        this.name = name;
    }
      
}

封装总结

封装与隐藏: 是面向对象的特征之一

一、问题的引入:

当我们创建一个类的对象以后,我们可以通过"对象.属性"的方式,对对象的属性进行赋值。这里,赋值操作要受到属性的数据类型和存储范围的制约。除此之外,没有其他制约条件。但是,在实际问题中,我们往往需要给属性赋值加入额外的限制条件。这个条件就不能在属性声明时体现,我们只能通过方法进行限制条件的添加。(比如:setLegs())同时,我们需要避免用户再使用"对象.属性"的方式对属性进行赋值。则需要将属性声明为私有的(private).

  • –>此时,针对于属性就体现了封装性。

二、封装性的体现:

  • 我们将类的属性xxx私有化(private),同时,提供公共的(public)方法来获取(getXxx)和设置(setXxx)此属性的值
  • 拓展:封装性的体现:① 如上 ② 不对外暴露的私有的方法 ③ 单例模式 …

三、封装性的体现,需要权限修饰符来配合。

  • 1.Java规定的4种权限(从小到大排列):private、缺省、protected 、public
  • 2.4种权限可以用来修饰类及类的内部结构:属性、方法、构造器、内部类
  • 3.具体的,4种权限都可以用来修饰类的内部结构:属性、方法、构造器、内部类
  •    修饰类的话,只能使用:缺省、public
    
  • 总结封装性:Java提供了4种权限修饰符来修饰类及类的内部结构,体现类及类的内部结构在被调用时的可见性的大小。

JavaBean

  • JavaBean是一种某些符合条件的特殊的类,但是必须遵守一定的规范
    • 类必须使用public修饰 – 类是公共的
    • 必须保证有公共无参数构造器,即使手动提供了带参数的构造器,也带手动提供无参数的构造器
    • 字段使用private修饰(私有化),每个字段提供一对getter和setter方法
public class User {

    private String name;
    private String uid;
    private int age;

    public User() {
    }

    public User(String name, String uid, int age) {
        this.name = name;
        this.uid = uid;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getUid() {
        return uid;
    }

    public void setUid(String uid) {
        this.uid = uid;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值