美文网首页JAVA学习之路
Java笔记-面向对象-封装

Java笔记-面向对象-封装

作者: 字节码 | 来源:发表于2016-12-18 12:43 被阅读202次
    • 类:确定对象将会拥有的特征(属性)和行为(方法)。
      类的特点:类是具有相同属性和方法的一组对象的集合。

    • 对象: 对象是唯一的
      创建对象:类名 对象名 = new 类名()
      使用对象:对象.属性 / 对象.方法名()

    • 成员变量与局部变量
      成员变量:在类中定义,用来描述对象将要有什么。(作用域在整个类内部都是可见的)
      局部变量:在类的方法中定义,在方法中临时保存数据。(作用域仅限于定义它的方法)

    定义一个Car类

    public class Car {
    
        String name;  // 名字
        String color; // 颜色
        int wheel;    // 轮子数量
        
        public void  reMake(String name) {
            
            this.name = name;
        }
    

    外界使用Car类创建对象

    package 面向对象;
    
    import 面向对象.Car;
    
    public class Demo1 {
    
        public static void main(String[] args) {
            // TODO Auto-generated method stub
    
            Car car = new Car();
            car.name = "奔驰";
            car.color = "白色";
            car.wheel = 6;
            
            car.reMake("BMW");
            System.out.println( car.name);
        }
    
    }
    
    
    • Java对象的内存分析:
      Car 这个类共有三个成员变量
    public class Car {
         String name; 
         String color;
         int wheel;   
    }
    /// 创建car对象
    Car c = new Car();
    c.name = "奔驰";
    c.color = "白色";
    c.wheel = 6;
    

    当使用Car类的声明一个c变量时
    在栈内存中开辟一块存储空间给c变量,堆内存中开辟存储空间给创建的这个对象及其成员变量,此时c变量记录这个对象的内存地址,会指向这个对象引用
    注意: 对象一旦被创建, 对象的成员变量也会分配默认的初始值,
    成员属性默认的初始值:
    int 0(默认值)
    float 0.0f(默认值)
    double 0.0(默认值)
    char ''(默认值)
    String(所有引用数据类型) null(默认值)

    • 成员变量与局部变量的区别:

      定义的位置上区别:
      1. 成员变量是定义在方法之外,类之内的。
      2. 局部变量是定义在方法之内。

      作用上的区别:
      1. 成员变量的作用是用于描述一类事物的公共 属性的。
      2. 局部变量的作用就是提供一个变量给方法内部使用而已。

      生命周期区别:
      1. 随着对象 的创建而存在,随着对象的消失而消失。
      2. 局部变量在调用了对应的方法时执行到了创建该变量的语句时存在,局部变量一旦出了自己的作用域
      那么马上从内存中消失。

      初始值的区别:
      1. 成员变量是有默认的初始值。
      数据类型 默认的初始值
      int 0
      float 0.0f
      double 0.0
      boolean false
      char ' '
      String(引用数据类型) null

        2. 局部变量是没有默认的初始值的,必须要先初始化才能使用。
      
    • 匿名对象:没有引用类型变量指向的对象称作为匿名对象。

    匿名对象要注意的事项:
    1. 我们一般不会给匿名对象赋予属性值,因为永远无法获取到。
    2. 两个匿名对象永远都不可能是同一个对象。

    匿名对象好处:简化书写。

    匿名对象的应用场景:
    1. 如果一个对象需要调用一个方法一次的时候,而调用完这个方法之后,该对象就不再使用了,这时候可以使用
    匿名对象。
    2. 可以作为实参调用一个函数。

    • JAVA中set()和get()方法的理解及使用

    set是设置的意思,而get是获取的意思,比如setAge()和getAge(),表示设置年龄和获取年龄
    然后我们来了解一下JAVA面向对象编程中的封闭性和安全性,封闭性即对类中的域变量进行封闭操作,即用private来修饰他们,如此一来其他类则不能对该变量访问。这样我们就将这些变量封闭在了类内部,这样就提高了数据的安全性,当我们想要操作这些域变量怎么办呢?我们可以通过两种方法,第一中即通过public方式的构造器(或称构造函数),对象一实例化就对该变量赋值。第二种就是通过上面提到的set和get方法,这里我举一个特定的例子,我定义一个Person类,该类中有name、age这两个私有域变量,然后我定义setname()、getname()、setage()、getage()这四个方法,通过这四个方法来实现对name和age的操作。这样一来,我不用直接对Person类中的域变量操作,而是通过set和get方法间接地操作这些变量,这样就能提高域变量的安全性,同时又保证了域变量的封装型。
    set和get方法的使用场景,一般来说set和get方法都是对私有域变量进行操作的,所以大多数都是使用在包含特定属性的类实体中。

    public class UserAccount {
    
        private String userName;
        private String sex;
        
        public void setUserName(String name) {
            userName = name;
        }
        
        public String getUserName() {
            return userName;
        }
        public void setSex(String str) {
            
            if (str.equals("男") || str.equals("女")) {
                sex = str;
            } else {
                sex = "男"; 
            }
        }
        public String getSex() {
            return sex;
        }
    }
    

    Java封装总结:
    概念:将类的某些信息隐藏在类内部,不允许外部程序直接访问,而是通过该类提供的方法类实现对隐藏信息的操作和访问。
    好处:只能同规定的方法访问数据,隐藏类的实现细节,方便修改和实现。
    实现步骤
    ① 修改属性的可见性:设为private
    ② 创建getter/setter方法:用于属性的读写
    ③ 在getter/setter方法中加入属性控制语句:对属性值的合法性进行判断

    封装的好处

    隐藏实际细节,提供公共的访问方式
    提高了代码的复用性
    提高安全性
    封装原则
    将不需要对外提供的内容都隐藏起来
    把属性隐藏,提供公共方法对其访问。

    • 构造函数:

    构造函数的作用: 给对应的对象进行初始化。

    构造函数的定义的格式:

    修饰符  函数名(形式参数){
        函数体...
    }
    

    构造函数要注意的细节:
    1. 构造函数 是没有返回值类型的。
    2. 构造函数的函数名必须要与类名一致。
    3. 构造函数并不是由我们手动调用的,而是在创建对应的对象时,jvm就会主动调用到对应的构造函数。
    4. 如果一个类没有显式的写上一个构造方法时,那么java编译器会为该类添加一个无参的构造函数的。
    5. 如果一个类已经显式的写上一个构造方法时,那么java编译器则 不会再为该类添加 一个无参 的构造方法。
    6. 构造函数是 可以在一个类中以函数重载 的形式存在多个 的。

    创建对象时,jvm虚拟机就会调用到对应的构造方法,构造方法从java编译器在编译的 时候给加上去的。

    jdk提供了一个java开发工具(javap)给我们进行反编译的,在终端敲javap会有相关提示操作指令。
    mac上javap的路径/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Home/bin
    javap 反编译工具的使用格式:

        javap -c -l -private 类名
    

    疑问: java编译器添加 的无参构造方法的权限修饰符是 什么?
    与类的权限修饰是一致的。

    构造函数与普通 函数的区别:
    1. 返回值类型的区别:
    1. 构造函数是没有返回值类型 的,
    2. 普通函数是有返回值类型的,即使函数没有返回值,返回值类型也要写上void。
    2. 函数名的区别:
    1. 构造函数的函数名必须要与类名一致,
    2. 普通函数的函数名只要符合标识符的命名规则即可。
    3. 调用方式的区别:
    1. 构造函数是 在创建对象的时候由jvm调用的。
    2. 普通函数是由我们使用对象调用的,一个对象可以对象多次普通 的函数,
    4. 作用上的区别:
    1. 构造函数 的作用用于初始化一个对象。
    2. 普通函数是用于描述一类事物的公共行为的。

    以下Baby类中提供了两个构造函数:
    //婴儿类
    class Baby{
        
        int id; //身份证
     
        String  name;  //名字
    
        //构造函数
        public  Baby(int i , String n){
            id  = i;
            name = n;
            System.out.println("baby的属性初始化完毕!!");
        }
    
        //无参 的构造函数
        public Baby(){
            System.out.println("无参的构造函数被调用了..");
        }
    
        public void cry(){
            System.out.println(name+"哇哇哭...");
        }   
    }
    
    • 构造代码块
      构造代码块的格式:

      {
      构造代码块
      }

    注意: 构造代码块的大括号必须位于成员 位置上。

    代码块的类别:
    1. 构造代码块。
    2. 局部代码块. 大括号位于方法之内。 作用:缩短局部 变量 的生命周期,节省一点点内存。
    3. 静态代码块 static
    构造 代码块要注意的事项:
    1. java编译器编译一个java源文件的时候,会把成员变量的声明语句提前至一个类的最前端。
    2. 成员变量的初始化工作其实都在在构造函数中执行的。
    3. 一旦经过java编译器编译后,那么构造代码块的代码块就会被移动构造函数中执行,是在构造函数之前执行的,构造函数的中代码是最后执行 的。
    4. 成员变量的显示初始化与构造代码块 的代码是按照当前代码的顺序执行的。

    • this关键字:

    this关键字代表了所属函数的调用者对象。

    this关键字作用:
    1. 如果存在同名成员变量与局部变量时,在方法内部默认是访问局部变量的数据,可以通过this关键字指定访问成员变量的数据。
    2. 在一个构造函数中可以调用另外一个构造函数初始化对象。

    this关键字调用其他的构造函数要注意的事项:
    1. this关键字调用其他的构造函数时,this关键字必须要位于构造函数中 的第一个语句。
    2. this关键字在构造函数中不能出现相互调用 的情况,因为是一个死循环。

    this关键字要注意事项:
    1. 存在同名的成员变量与局部变量时,在方法的内部访问的是局部变量(java 采取的是“就近原则”的机制访问的。)
    2. 如果在一个方法中访问了一个变量,该变量只存在成员变量的情况下,那么java编译器会在该变量的 前面添加this关键字。

    this关键字调用其他的构造函数要注意的事项:
    1. this关键字调用其他的构造函数时,this关键字必须要位于构造函数中 的第一个语句。
    2. this关键字在构造函数中不能出现相互调用 的情况,因为是一个死循环。
    还有就是注意:this不能用在static方法中!所以甚至有人给static方法的定义就是:没有this的方法!虽然夸张,但是却充分说明this不能在static方法中使用!

    • static关键字
      static静态变量(也称类成员)
      静态的成员变量只会在数据共享区中维护一份,而非静态成员变量的数据会在每个对象中都维护一份的。。
      它属于整个类所有,而不是某个对象所有,被类的所有对象所共享。
      静态成员可使用类名直接访问,也可以使用对象名进行访问。
      静态成员属于整个类,当系统第一次使用该类时,就会为其分配内存空间直到该类被卸载才会进行资源回收。

    static静态函数

    1. static修饰成员变量 :如果有数据需要被共享给所有对象使用时,那么就可以使用static修饰。
        
        静态成员变量的访问方式:
                
                方式1: 可以使用对象进行访问。
                    格式: 对象.变量名。
                
                方式二: 可以使用类名进行访问。
                    格式: 类名.变量名;
    
            注意: 
                1. 非静态的成员变量只能使用对象进行访问,不能使用类名进行访问。
                2. 千万不要为了方便访问数据而使用static修饰成员变量,只有成员变量的数据是真正需要被共享的时候
                才使用static修饰。
            
        static修饰成员变量的应用场景: 如果一个数据需要被所有对象共享使用的时候,这时候即可好实用static修饰。
    

    静态代码块:

    static {
      /// 要执行的语句
    }
    

    静态代码块是在不管有没有创建对象,只要类被加载到内存中的时候执行的;
    一个类的文件加载是懒加载,是在要使用到这个类的时候加载到内存中的,而静态代码块是在类文件加载的时候执行的

    static(静态、修饰符)

    static修饰成员变量时:static修饰成员变量时,那么该成员变量的数据就是一个共享的数据.
    
        静态成员变量的访问方式:
            
                方式一: 使用对象进行访问。
                        对象.属性名
                方式二:可以使用类名进行访问。
                        类名.属性名
        注意:
            1. 非静态成员变量不能类名直接访问,只能使用对象进行访问。
            2. 千万不要为了方便访问成员变量而使用static修饰,一定要是该数据是共享数据 时才使用static修饰。
    
    static修饰方法(静态的成员方法):
        
        访问方式:
            
            方式一:可以使用对象进行访问。
                    对象.静态的函数名();
    
            方式二:可以使用类名进行访问。
                    类名.静态函数名字。
        
        推荐使用是类名直接访问静态的成员。
    

    静态的成员变量与非静态的成员变量的区别:
    1. 作用上的区别:
    1. 静态的成员变量的作用共享一个 数据给所有的对象使用。
    2. 非 静态的成员变量的作用是描述一类事物的公共属性。
    2. 数量与存储位置上的区别:
    1. 静态成员变量是存储方法 区内存中,而且只会存在一份数据。
    2. 非静态的成员变量是存储在堆内存中,有n个对象就有n份数据。
    3. 生命周期的区别:
    1. 静态的成员变量数据是随着类的加载而存在,随着类文件的消失而消失。
    2.非静态的成员数据是随着对象的创建而存在,随着 对象被垃圾回收器回收而消失。

    静态函数要注意的事项:
    1. 静态函数是可以用类名或者对象进行调用的,而非静态函数只能使用对象进行调用。
    2. 静态的函数可以直接访问静态的成员,但是不能直接访问非静态的成员。
    原因:静态函数是可以使用类名直接调用的,这时候可能还没有存在对象,
    而非静态的 成员数据是随着对象 的存在而存在的。

    3. 非静态的函数是可以直接访问静态与非静态的成员。
        原因:非静态函数只能由对象调用,当对象存在的时候,静态数据老早就已经存在了,而非静态
        数据也随着对象的创建而存在了。
    
    4. 静态函数不能出现this或者super关键字。
        原因:因为静态的函数是可以使用类名调用的,一旦使用类名调用这时候不存在对象,而this
        关键字是代表了一个函数 的调用者对象,这时候产生了冲突。
    

    静态的数据的生命周期:静态的成员变量数据是优先于对象存在的。

    static什么时候修饰一个函数?

    如果一个函数没有直接访问到非静态的成员时,那么就可以使用static修饰了。 一般用于工具类型的方法
    

    静态函数不能访问非静态的成员?
    静态函数只要存在有对象,那么也可以访问非 静态的数据。只是不能直接访问而已。

    • Java中的main()方法简单理解

    在Java中,main()方法是Java应用程序的入口方法,也就是说,程序在运行的时候,第一个执行的方法就是main()方法,这个方法和其他的方法有很大的不同,比如方法的名字必须是main,方法必须是public static void 类型的,方法必须接收一个字符串数组的参数等等。

    public static void main(String[] args) {
        System.out.println("Hello world");  
        }
    

    这个main()方法的声明为:public static void main(String args[])。必须这么定义,这是Java的规范。

    为什么要这么定义,和JVM的运行有关系。
    当一个类中有main()方法,执行命令“java 类名”则会启动虚拟机执行该类中的main方法。

    由于JVM在运行这个Java应用程序的时候,首先会调用main方法,调用时不实例化这个类的对象,而是通过类名直接调用因此需要是限制为public static。

    对于java中的main方法,jvm有限制,不能有返回值,因此返回值类型为void。
    main方法中还有一个输入参数,类型为String[],这个也是java的规范,main()方法中必须有一个入参,类细必须String[],至于字符串数组的名字,这个是可以自己设定的,根据习惯,这个字符串数组的名字一般和sun java规范范例中mian参数名保持一致,取名为args。

    因此,main()方法定义必须是:“public static void main(String 字符串数组参数名[])”。

    • Java的单例设计模式

    • 单例模式的定义
      一个类有且仅有一个实例,并且自行实例化向整个系统提供。

    • 单例模式的作用
      简单说来,单例模式的作用就是保证在整个应用程序的生命周期中,任何一个时刻,单例类的实例都只存在一个(当然也可以不存在)。

    • 单例设计模式类图.png
    • 代码体现:

    (1)私有化构造函数

    (2)创建私有并静态的本类的对象

    (3)定义公有并静态的方法,返回该对象;

    代码实现主要有两种方式:饿汉模式和懒汉模式:

    饿汉模式:类加载的时候对象就已经存在,饿汉式是线程安全的,在类创建的同时就已经创建好一个静态的对象供系统使用,以后不再改变

    private Singleton() {
            
        }
        /// 由于是静态成员变量 -- 不管外界有没有使用, 当类加载到内存中时,就会创建一个对象
        private static Singleton singleton = new Singleton();
        
        public static Singleton getInstance() {
            return singleton;
        }
    

    懒汉模式:类加载的时候对象还不存在,就是所谓的延迟加载方式,需要时再进行创建,懒汉式如果在创建实例对象时不加上synchronized则会导致对对象的访问不是线程安全的

        private Singleton() {
            
        }
    
        private static Singleton s = null;
        
        public static Singleton getInstance() {
            if (s == null) {
                s = new Singleton();
            }
            
            return s;
        }
    

    懒汉式的线程不安全性,通常情况下,我们建议写饿汉式,因为是线程安全的
    两个线程,线程一和线程二同时调用了getInstance方法,当线程1执行了if判断,single为空,还没来得及执行single =new Single()创建对象,这个时候线程2就来了,它也进行if判断,single依然为空,则创建Single对象,此时,两个线程就会创建两个对象,违背我们单例模式的初衷,如何解决呢?

    出现线程安全的问题,为了解决这种问题,加入同步机制:静态同步函数的锁是类的字节码文件对象

    单例模式总结:
    1.单例模式是用来实现在整个程序中只有一个实例的。
    2.单例类的构造函数必须为私有,同时单例类必须提供一个全局访问点。
    3.单例模式在多线程下的同步问题和性能问题的解决。
    4.懒汉式和饿汉式单例类。

    相关文章

      网友评论

        本文标题:Java笔记-面向对象-封装

        本文链接:https://www.haomeiwen.com/subject/loaomttx.html