zoukankan      html  css  js  c++  java
  • Java中你必须知道的基础知识点


    本篇博客主要记录Java中面向对象的概念知识和一些基础Java类的使用。属于自己平时学习过程中知识点的“拼凑”,方便自己回顾总结。


    1. 什么是面向对象

    面向对象是一种优秀的软件设计思想,是相对于面向过程、面向切面等设计思想的一种软件设计理念。它的核心思想是运用更加贴近人类思维的方式去设计软件,将软件中的各个组件抽象成相应的类,再将这些类组装成我们所需的软件系统。这里举个例子,假如用面向对象的方式设计一个电脑,我们会设计CPU类、硬盘类、显示器类、内存类等等,然后将这些类组合在一起设计成Computer类。

    面向过程的思想在解决问题时会将问题分解成一个个小的函数,然后按照某种顺序去执行这些方法,当这些方法执行完毕,问题也就解决了。

    2. 三大基本特征和五项基本原则

    面向对象的三个基本特征是:封装、继承和多态。正是基于这些特征,面向对象的开发语言才能拥有更好的可重用性、扩展性和维护性。

    • 封装:将对象的实现细节隐藏起来,然后通过一些公共的方法向外部提供该对象的功能;
    • 继承:继承是软件复用的一种重要手段,子类继承父类之后将直接获得父类的属性和方法;
    • 多态:对象可以赋给父类对象和接口,但是运行时依然表现出子类或实现类的特征。

    面向对象的五大原则如下:

    • 单一职责原则(SRP):一个类专注于实现一个功能;
    • 开闭原则(OCP):对象或实体应该对扩展开放,对修改封闭;
    • 里氏替换原则(LSP):子类可以替换父类并且出现在父类能够出现的任何地方,这就需要我们面向接口编程;
    • 依赖倒置原则(DIP):高层次的模块不应该依赖于低层次的模块,他们都应该依赖于抽象;抽象不应该依赖于具体实现,具体实现应该依赖于抽象;
    • 接口隔离原则(ISP):使用多个专门的接口比使用单个接口要好的多。在实际编程中,为了减少接口的定义,将许多方法都放在一个接口中,最后发现,维护和实现接口的时候会花费很多精力。而接口所定义的操作相当于对客户端的一种承诺,这种承诺当然是越少越好,越精练越好,过多的承诺带来的就是你的大量精力和时间去维护。

    3. Java的平台无关性

    Java语言能跨平台的关键是JVM能跨平台。JVM还支持的语言有Kotlin、Groovy、JRuby、Jython、Scala等。

    4. 值传递和引用传递

    基本数据类型,保存的是数据本身的值,按值传递;引用类型的变量保存的是对象在内存中的地址,按引用传递(引用传递可以看成是一种特殊的值传递)。

    5. 方法重载和重写

    方法重载是指在同一个类中存在多个方法名相同,但是方法参数不用的方法;

    方法重写是指子类继承父类后,重新修改了父类的某个方法的行为(子类中存在这样一个方法,这个方法的方法名方法参数都和父类中某个方法一样,但是这个两个方法的方法体不一样,这种情况我们称子类方法重写了父类方法)

    6. 基本数据类型

    Java中有8种基本数字类型。从大类上分的话分别是布尔型,字符型,整形和浮点型。对应bool,byte,char,short,int,long,float和double类型。

    • byte:一个字节,8个bit位,-2^7 ~ 2^7-1
    • char : 2个字节,16个bit位,0 ~ 2^16-1 ;
    • short:2个字节,16个bit位,-2^15 ~ 2^15-1
    • int:4个字节,32个bit位,-2^31 ~ 2^31-1
    • long:8个字节,64个bit位,-2^63 ~ 2^63-1
    • float:4个字节,32个bit位
    • double:8个字节,64个bit位。

    在计算机中,浮点数用来近似表示任意某个实数。浮点数分为双精度浮点数和单精度浮点数。单精度占4个字节,双精度占8个字节,表示的范围更大。在要求精确计算的场合,不建议使用浮点型数据。因为浮点数计算的结果不是很精确,是近似的结果。这种情况应该使用BigDecimal。这边举个BigDecimal使用的简单列子:

    BigDecimal bigDecimal1 = new BigDecimal(String.valueOf(1.1));
    BigDecimal bigDecimal2 = new BigDecimal(String.valueOf(2.223));
    String str1 = bigDecimal1.add(bigDecimal2).toString();
    
    //减法
    bigDecimal1 = new BigDecimal(String.valueOf(2.2));
    bigDecimal2 = new BigDecimal(String.valueOf(10.1));
    String str2 = bigDecimal1.subtract(bigDecimal2).toString();
    //乘法
    bigDecimal1 = new BigDecimal(String.valueOf(1.1));
    bigDecimal2 = new BigDecimal(String.valueOf(2.234));
    String str3 = bigDecimal1.multiply(bigDecimal2).toString();
    //除法
    bigDecimal1 = new BigDecimal(String.valueOf(4.4));
    bigDecimal2 = new BigDecimal(String.valueOf(3));
    //除法需要设置精度和四舍五入的方式
    String str4 = bigDecimal1.divide(bigDecimal2,3, RoundingMode.HALF_UP).toString();
    //结果
    System.out.println("加法结果:" + Double.valueOf(str1));
    System.out.println("减法结果:" + Double.valueOf(str2));
    System.out.println("乘法结果:" + Double.valueOf(str3));
    System.out.println("除法结果:" + Double.valueOf(str4));
    

    7. 包装类型

    包装类型是相对于基本数据类型来讲的。Java中有8种基本数据类型,每个基本数据类型都有相对的包装类型。比如int的包装类型是Integer。包装类型是引用类型,而且都是不可变类。

    • 自动装箱:将基本数据类型赋值给包装类型的过程,实现原理是编译器层面new了一个包装类再赋值给相应的变量;
    • 自动拆箱:包装类型直接赋值给基本数据类型,实现原理类似,也是编译器层面调用了包装类的getValue方法再赋值给对应的基本数值类型。

    比较有趣的是,包装类型在加载的过程中都会缓存某些值的类。比如Integer会缓存-128到127的类。

    //不会使用缓存的数据
    Integer num1 = new Integer(1); 
    //会使用缓存的数据
    Integer num2 = 1;
    

    通过设置-XX:AutoBoxCacheMax=?这个参数,可以调整Integer缓存的最大值。当然其他包装类型也有类似的行为,Byte、Short和Long都缓存了-128到127的类,Character缓存了0到127的类,但是这些类不能像Integer那样修改缓存的最大值。

    8. String类

    String是我们开发过程中使用的最多的一个类。它是一个不可变类,不能被继承。String类常用的方法如下图。另外String还有一个format方法可以进行非常丰富的格式化功能。具体的使用方式可以参考这篇博客

    8.1 subString方法的原理

    public final class String
        implements java.io.Serializable, Comparable<String>, CharSequence {
        /** The value is used for character storage. */
        private final char value[];
    
        /** Cache the hash code for the string */
        private int hash; // Default to 0
    
        /** use serialVersionUID from JDK 1.0.2 for interoperability */
        private static final long serialVersionUID = -6849794470754667710L;
    	
    }
    

    String的类别是用char数组实现的,从代码中可以看到char数组用final修饰了,所以是不可变的。调用String的subString方法其实是又重新new了一个新的String对象:

    public String substring(int beginIndex, int endIndex) {
        if (beginIndex < 0) {
            throw new StringIndexOutOfBoundsException(beginIndex);
        }
        if (endIndex > value.length) {
            throw new StringIndexOutOfBoundsException(endIndex);
        }
        int subLen = endIndex - beginIndex;
        if (subLen < 0) {
            throw new StringIndexOutOfBoundsException(subLen);
        }
        return ((beginIndex == 0) && (endIndex == value.length)) ? this
                : new String(value, beginIndex, subLen);
    }
    

    8.2 repalce函数

    • replace(char oldChar, char newChar):使用newChar替换所有的oldChar,不是基于正则表达式的;
    • replace(CharSequence target, CharSequence replacement):替换所有,基于正则表达式的;
    • public String replaceFirst(String regex, String replacement):替换regex匹配的第一个字符串,基于正则表达式;
    • replaceAll(String regex, String replacement):替换regex匹配的所有字符串,基于正则表达式;

    8.3 valueOf函数

    String提供了很多valueOf函数,比如valueOf(int i)、valueOf(double i)等。其实背后调用的是对应包装类的toSting方法

    public static String valueOf(int i) {
        return Integer.toString(i);
    }
    //Integer的toString方法
    public static String toString(int i) {
        if (i == Integer.MIN_VALUE)
            return "-2147483648";
        int size = (i < 0) ? stringSize(-i) + 1 : stringSize(i);
        char[] buf = new char[size];
        getChars(i, size, buf);
        return new String(buf, true);
    }
    

    8.3 常量池(来源于互联网)

    常量池可以分为Class常量池、运行时常量池和字符串常量池:

    1. class文件常量池
      在Class文件中除了有类的版本、字段、方法、接口等描述信息外,还有一项信息是常量池(Constant Pool Table),用于存放编译期生成的各种字面量和符号引用。下面对字面量和符号引用进行说明。

    字面量类似与我们平常说的常量,主要包括以下两种

    • 文本字符串,例如String a = "aa"。其中"aa"就是字面量。
    • 被final修饰的变量。

    符号引用包括以下形式:

    • 类和接口和全限定名:例如对于String这个类,它的全限定名就是java/lang/String。
    • 字段的名称和描述符:所谓字段就是类或者接口中声明的变量,包括类级别变量和实例级的变量。
    • 方法的名称和描述符:所谓描述符就相当于方法的参数类型+返回值类型。
    1. 运行时常量池
      我们知道类加载器会加载对应的Class文件,而上面的class文件中的常量池,会在类加载后进入方法区中的运行时常量池【此时存在在内存中】。并且需要的注意的是,运行时常量池是全局共享的,多个类共用一个运行时常量池。并且class文件中常量池多个相同的字符串在运行时常量池只会存在一份。注意运行时常量池存在于方法区中。

    2. 字符串常量池
      看名字我们就可以知道字符串常量池会用来存放字符串,也就是说常量池中的文本字符串会在类加载时进入字符串常量池。那字符串常量池和运行时常量池是什么关系呢?上面我们说常量池中的字面量会在类加载后进入运行时常量池,其中字面量中有包括文本字符串,显然从这段文字我们可以知道字符串常量池存在于运行时常量池中。也就存在于方法区中。到了JDK1.7时,字符串常量池就被移出了方法区,转移到了堆里了。那么我们可以推断,到了JDK1.7以及之后的版本中,运行时常量池并没有包含字符串常量池,运行时常量池存在于方法区中,而字符串常量池存在于堆中。

    程序运行时,除非手动向常量池中添加常量(比如调用intern方法),否则jvm不会自动添加常量到常量池。

    8.4 intren方法

    intren方法的作用是检测常量池中是否有当前字符串,有的话就返回常量池中的对像,没有的话就将当前对像放入常量池。

    8.5 兄弟类之间的比较

    公众号推荐

    欢迎大家关注我的微信公众号「程序员自由之路」

  • 相关阅读:
    Transformer详解
    PAT 1012
    PAT 1011
    PAT 1010
    Jordan Lecture Note-3: 梯度投影法
    PAT 1009
    PAT 1008
    Jordan Lecture Note-2: Maximal Margin Classifier
    PAT 1007
    PAT 1006
  • 原文地址:https://www.cnblogs.com/54chensongxia/p/11509067.html
Copyright © 2011-2022 走看看