• Java对象和类(封装)


    Java对象和类(封装)

    面向对象

    传统的程序设计方式是面向过程的,然而面向过程方式设计程序有很多缺点:

    1. 在某些场景,面向过程不符合物理世界的表现方式;而面向对象更加符合。
    2. 在大规模开发中,面向过程设计的程序有很多过程,操作很多全局变量,难以调试;而采用面向对象,可以将不同的过程、变量封装到不同的类中,降低程序耦合性,便于协作开发、调试。

    类和对象

    1. 类是一组数据概念以及定义在其上的操作的集合,类没有实体,只存在于概念上。

    2. 对象是类的实体,类的一个特例,比如人是类概念,小明这个人是人的实体对象。

    3. 程序设计中识别类:在分析问题的过程中出现的名词,很多都对应类(或者是基本数据类型),而对应的动词则对应了对应的操作。

    4. 类之间的关系:依赖(use-a)、聚合(has-a)、继承(is-a)

    预定义类和对象的使用

    包括创建、修改、丢弃(gc自动回收)、setter、getter等。

    自定义类

    类一般由构造、属性、方法组成。

    构造

    构造的特点:

    1. 构造与类同名
    2. 构造无返回值
    3. 构造可以有任意多个参数
    4. 构造可以重载
    5. 构造伴随new关键字

    重载

    构造可以重载。

    如果没有显示定义构造,则java自动生成一个默认无参构造,将所有未初始化的域设置为默认值。

    然而一旦显示定义了一个构造,不管是不是无参构造,java都不会再提供默认构造

    初始化代码块

    在类声明时,可以定义一个或者多个初始化代码块,只要构造对象,初始化代码块就会执行。如:

    package com.ame;
    
    public class Employee {
        private static int nextId;
    
        private int id;
        private String name;
        private double salary;
    
        //初始化代码块
        {
            id = nextId;
            nextId++;
        }
        
        public Employee(String name, double salary) {
            this.name = name;
            this.salary = salary;
        }
    
        public Employee() {
            name = "";
            salary = 0;
        }
    }
    
    

    不论使用哪个构造,都会在构造执行之前初始化代码块。如果有多个代码块,则按序执行。

    初始化代码块可以用static修饰,用于类加载时执行(只执行一次),初始化静态域。如:

    package com.ame;
    
    public class Employee {
        private static int nextId;
    
        private int id;
        private String name;
        private double salary;
    
        static {
            nextId = 2;
            System.out.println("static.");
        }
    
        //初始化代码块
        {
            id = nextId;
            nextId++;
            System.out.println("id:" + id);
        }
    
        public Employee(String name, double salary) {
            this.name = name;
            this.salary = salary;
        }
    
        public Employee() {
            name = "";
            salary = 0;
        }
    
        public static void main(String[] args) {
            new Employee();
            new Employee();
            new Employee("", 0);
        }
    }
    
    

    执行结果:

    static.
    id:2
    id:3
    id:4
    

    析构

    C++中有显示析构方法,当对象被弃用的时候进行清理。

    然而java有垃圾回收机制,不提供析构。

    但是考虑到当对象不再使用时可能需要释放一些外部资源(如打开的文件),因此在java中,可以为类添加finalize方法,finalize将在垃圾回收前调用,但是具体的调用时间不确定(因此尽量不要依赖fnialize方法进行回收)。

    方法

    方法的参数分为隐式参数和显示参数。

    隐式参数即this指针,this指向调用该方法的对象。

    显示参数即为方法声明时显示定义的参数。

    方法调用的参数为值传递方式,也就是说在传参时会进行一次拷贝。

    ​ 注意:引用类型传参的时候只是将变量值(指针或地址)进行拷贝了,但拷贝后的指针仍然指向最初的对象。

    所有的方法可以进行重载,重载只要求同名不同参。

    属性

    1. 强烈建议类中的属性设为私有,然后为私有的属性提供setter和getter方法。

      这样做有很多好处,例如可以在setter方法中对操作的合法性进行校验。

    2. 尽量不要返回对象私有属性的引用。而应该返回其拷贝(clone方法)。

    3. 不可变的属性应该用final修饰。

      final域只能在初始化时被赋值一次。

      注意:final域变量不可变并不意味这所指向的对象不可变。

    4. 属性初始化一般有三种方式:默认值(尽量不要这样)、声明时赋值、构造赋值、静态初始化代码赋值。

    基于类的访问权限

    方法可以访问类所有的对象的私有数据。如:

    package com.ame;
    
    import java.util.Objects;
    
    public class Person {
        private int id = 0;
    
        public Person(int id) {
            this.id = id;
        }
    
        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
            Person person = (Person) o;
            return id == person.id;//这里通过person引用访问了私有属性id
        }
    
        @Override
        public int hashCode() {
            return Objects.hash(id);
        }
    }
    

    静态域和静态方法

    静态域和静态方法用static修饰,静态成员由类所拥有,不属于具体的对象,通过类名访问。

    静态域有静态变量、静态常量。

    静态方法和普通的方法相比,没有this指针这个隐式参数,但是可以访问自身所在类的静态成员。

    一般的main方法是一个常见的静态方法,也是java代码执行的入口。

    java使用包组织类,将类按照包放在一起,不同包中的类可以同名,对于java编译器来说,嵌套的包是两个包,如java.util和java.util.jar是两个无关联的包(只是名字有重叠而已)。

    包的使用

    略。

    包的导入

    使用一个包中的类,可以通过全限定名访问,也可以通过import引入。如:

    package com.ame;
    
    import java.util.Random;//导入Random
    
    public class Main {
        public static void main(String[] args) {
            java.util.Date d = new java.util.Date();//全限定名直接访问
            System.out.println(d);
    
            Random random = new Random();//类名访问
            System.out.println(random.nextInt());
        }
    }
    
    

    执行结果:

    Fri Jul 31 09:27:52 GMT+08:00 2020
    400450209
    

    假如两个包中有同名类,比如java.util.Date和java.sql.Date,那么一般按照下面所述进行处理:

    1. 两者若导入的形式都是import .*,直接使用类名Date会发生冲突,无法编译,因为根据类名Date匹配到了两个类(不用Date则不会错)。

      import java.util.*;
      import java.sql.*;
      /*
      * 不使用Date类就不会报错,用了Date类才会报错
      */
      
    2. 若两者都是import .Date形式,则由于引入的类名冲突,编译错误(还没用Date就错了)。

      import java.util.Date;
      import java.sql.Date;
      /*
      * 两个import冲突,引入时就会错。
      */
      
    3. 如两者导入形式不同(一个import .*,一个import .Date(也可以加上import .*))则后者优先级更高,可以使用类名Date(后者)

      import java.util.*;//可要可不要
      import java.sql.*;
      import java.util.Date;
      /*
      * 通过类名Date只能使用java.util.Date
      * 但仍然可以通过全限定名访问java.sql.Date访问java.sql.Date类。
      */
      
    4. 若两者都需要使用,则只能最多显示引入(通过全限定名引入)一个,然后对没有显示引入的类使用全限定名进行访问。

    静态引入

    import语句除了引入类,还可以用来引入类中的静态成员,如:

    package com.ame;
    
    import static java.lang.Math.*;
    
    public class Main {
        public static void main(String[] args) {
            System.out.println(PI);//没有通过Math类名,直接使用了Math.PI
        }
    }
    
    

    执行结果:

    3.141592653589793
    

    包作用域

    对于类、类中成员,如果使用public修饰,代表完全公开,所有类的所有成员都可以访问的;

    如果使用private修饰(类不能用private,仅限于类中成员),代表完全私有,只有定义他们的类可以访问;

    如果不使用修饰符或使用protected(默认修饰符)修饰,则代表受保护,仅同一个包中的类中方法可以访问到该成员,而包以外的不能访问。

  • 相关阅读:
    程序员那些事
    Android studio导入eclipse工程时出现中文全部乱码问题
    环境搭建贴
    Android涉及到的网址都记录在这把~~~~
    好书记录
    网络资源整理
    C# 资源
    samba 服务器
    我的虚拟机上网记录
    共享资源链接
  • 原文地址:https://www.cnblogs.com/black-watch/p/13409096.html
Copyright © 2020-2023  润新知