首页 > 编程语言 >Java lang

Java lang

时间:2022-12-03 23:33:47浏览次数:39  
标签:lang Java String 子类 枚举 实例 方法 final

目录

lang

系统会自动加载 java.lang 包,而不用 import 导入,所以我们可以直接取用其中的所有类。

1.System

System 为 final。

System 类提供的功能包括

  • 标准输入、标准输出和错误输出流
  • 访问外部定义的属性和环境变量
  • 一种加载文件和库的方法
  • 一种用于快速复制数组的一部分的实用方法

标准输入、标准输出和错误输出流

获取 System 的 PrintStream 类型的静态成员变量 in、out、err,调用相关方法实现标准输入、标准输出和错误输出流。

访问外部定义的属性和环境变量

通过 getProperty 方法可获取当前系统的属性:

通过 env 方法可获取当前系统的环境变量。

通过Runtime.getRuntime().availableProcessors()可以获得处理器的数量。

2.Enum

Enum 是所有 Java 语言枚举类型的公共基类,所有枚举类都继承它。当定义一个枚举类时,该枚举类相当于 Enum 的子类,而枚举类中的枚举成员,相当于该枚举类的一个实例,这些枚举成员默认都被 final、public、static 修饰。

Enum 中包含两个重要的成员变量:name、ordinary。name 为枚举成员(实例)的名称,但最好使用 toString 方法而不是访问该字段。ordinary 表示枚举成员(实例)的序数,即它在枚举类中声明时的位置(默认从 0 开始)。而 name 和 ordinary 方法,分别返回 name 和 ordinary。

Enum 有唯一一个构造方法,被 protected 修饰。它是只供给编译器的方法,来创造对应枚举类的实例。

Enum 的 valueOf 方法,可根据提供的枚举类和枚举成员名,返回对应的枚举类实例。

除此之外,Enum 还提供 hashCode、getDeclaringClass 等方法,Enum 也实现了 Comparable 接口,提供 compareTo 方法。Enum 的 toString 方法实现是返回 name,与 name 方法一样,但不同的是, name 被 final 修饰,toString 方法可以被重载。

对于枚举类中的方法。valueOf 方法可根据传递枚举成员名 name 返回对应的枚举实例,但如果没有该实例,则会抛出异常。可调用 values 方法,返回所有该枚举类的所有枚举实例的数组。

枚举类不可以被继承,但可以实现接口。

枚举构造函数不可以访问枚举类的静态字段,除非是编译器常量,因为构造时,静态域可能还没有被初始化。具体的原因是,枚举常量也是静态 final 的,对于静态字段,是按照声明的顺序初始化,因此,在枚举构造函数中不能访问静态域。因此,如果需要访问静态域,可以选择静态初始化块。还需要注意的是:枚举常量总是最先声明的,所以静态初始化块总是在枚举常量实例构造完成后执行。

3.Throwable

Java 中定义类异常类,这些类都是 Throwable 的子类。而 Throwable 派生了两个子类, Exception 和 Error。

Error

Error 是 JVM 抛出的,描述了 Java 运行系统中的内部错误以及资源耗尽的情景。如果发生,除了尽力使程序安全退出外,在其他方面是无能为力的。

常见的有 IOError、LinkageError。

Exception

Exception 是程序自身可以处理的异常。可分为两类:CheckedException 与 RuntimeException。

1.CheckedException

一般指外部错误,发生在编译阶段。编译器会强制程序去捕获这类异常而在代码中进行处理。

常见的有 IOException、SQLException。

2.RuntimeException

一般发生在 JVM 正常运行阶段。通常指程序运行时出现的错误,程序虽然能通过语法检查,但是最终被迫中止运行。

常见的有 NullPointerException、ClassCastException、IndexOutOfBoundException、IllegalArgumentException、ArrayStoreException、ArithmeticException、BufferOverflowException。

Return 与 finally 的执行顺序

finally 语句是肯定会执行的,对于 return 与 finally 的执行顺序如下:

1.return 语句的返回值计算,结果保存在操作数栈顶

2.操作数栈顶值复制到局部变量区作为返回值。

3.执行 finally 代码块代码。

4.将局部变量区的返回值又复制回操作数栈顶。

5.执行 return 指令,返回操作数栈顶的值。

我们可以看到,在第一步执行完毕后,整个方法的返回值就已经确定了,由于还要执行 finally 代码块,因此程序会将返回值暂存在局部变量区,腾出操作数栈用来执行 finally 语句块中代码,等 finally 执行完毕,再将暂存的返回值又复制回操作数栈顶。所以无论 finally 语句块中执行了什么操作(除了return语句,因为会导致提前返回),都无法影响返回值,所以试图在 finally 语句块中修改返回值是徒劳的。因此,finally语句块设计出来的目的只是为了让方法执行一些重要的收尾工作,而不是用来计算返回值的

4.类型、值和变量

Java是静态类型(statically typed)语言,即所有的变量和表达式的类型在编译时都是确定的。Java还是一个强类型(strongly typed)的语言,类型限制了变量可以存储的值以及类型所能支持的操作。静态强类型有助于在编译器检测错误。

Java的类型分为两类:原始类型(primitive types)和引用类型(reference types)

所有的原始类型在所有的 JVM 实现中都是同一长度,与机器无关。原始类型包括:boolean、byte、char、short、int、long、float、double。引用类型包括数组类型、对象类型、接口类型、类型变量null 是特殊的引用类型,并且可以被复制和 cast 到任何的引用类型

需要特殊说明的是类型变量,类型变量是一个泛型类,接口,方法或者构造函数的类型参数。每一个类型变量具有一个 bound,如果一个类型变量没有显式的说明,那么它的 bound 就是 Object。

整型类型以及范围:

  • byte:8 bit,范围为[-128, 127]
  • short:16 bit,范围为[-32768, 32767]
  • int:32bit,范围为[-2147483648, 2147483647]
  • long:64 bit,范围很大
  • char:16 bit,范围['\u0000', '\uffff']也就是[0, 65535]

浮点类型:

Object 类是所有其他类的超类。所有数组和类类型都继承于 Object,Object 包含了以下方法:

  • clone,用于复制对象。
  • equals,基于值的等价定义。
  • finalize,在对象销毁之前运行的函数。
  • getClass,获取对象的 Class 对象。
  • hashCode,计算 Object 的 hash 值,可以用于对象相等的判断,以及唯一判断。
  • wait,notify 和 notifyAll 用于并发编程的线程中使用。
  • toString,对象的 String 表示

5.String

// TODO 03/12/2022 meyok: 自己做总结整理。

String 代表字符序列,所有的字符串都是 String 类的一个实例。String 是常量,不可变,并且是 final 类

String 在创建之后就不能改变,可以使用StringBuilder 或者 StringBuffer 进行构造新的字符串。

String 包含了用于检查单个字符,比较字符串,查找字符串,获取子串,创建或复制大小写形式的字符串。

Java 还对 + 操作符(concatenation operation)进行了重载,提供了 String 和其他类之间的连接,主要是通过 StringBuilder 实现。

String 实现了 CharSequence,CharSequence 接口是一个统一的只读的 char 序列接口。

字符串对象相等

package com.jack.java.lang; 

public class LangTest { 

    public static void main(String[] args) { 

        /* 
        * Java虚拟机中存在一个字符串池,保存了String对象,由于String是immutable类型,因此可以共享 
        * 可以调用String的intern()来访问字符串池 
        * */ 
        String s1 = "abc"; 
        // 在字符串池中存在abc,因此共享 
        String s2 = "abc"; 
        System.out.println("s1 == s2:" + (s1 == s2)); //true 
        System.out.println("s1.equals(s2): " + s1.equals(s2)); //true 

		/* 
        * s3本质上要创建两个对象,第一个存放在字符串池中的"abc",第二个是存在于堆区的s3引用的对象。 
        * 此外s3引用在栈中 
        * */ 
        String s3 = new String("abc"); 
        String s4 = new String("abc"); 
        System.out.println("s3 == s1:" + (s3 == s1)); //false 
        System.out.println("s3.equals(s1): " + s3.equals(s1)); //true 
        //s3 s4指向堆区的字符对象,堆区的地址不同 
        System.out.println("s3 == s4:" + (s3 == s4)); //false 
        System.out.println("s3.equals(s4): " + s3.equals(s4)); //true 

        /* 
        * 常量在编译器决定,因此两者相等 
        * */ 
        String str1 = "ab" + "cd"; 
        String str11 = "abcd"; 
        System.out.println("str1 == str11: " + (str1 == str11)); //true 
        /* 
        * str2,str3在编译时就已经分配字符串常量的地址, 
        * 但是由于str2,str3是对象,因此必须使用StringBuilder来完成str4的构建。 
        * 所以str4实际会创建StringBuilder,然后调用toString创建一个在堆区的对象 
        * 因此str4不等于str5 
        * str4和str6都需要在运行期才能解析 
        * */ 
        String str2 = "ab"; 
        String str3 = "cd"; 
        String str4 = str2 + str3; 
        String str5 = "abcd"; 
        System.out.println("str4 == str5: " + (str4 == str5)); //false 

        String str6 = "b"; 
        String str7 = "a" + str6; // 原理类似 
        String str67 = "ab"; 
        System.out.println("str7 == str67: " + (str7 == str67)); //false; 

        /* 
        * 由于str8是常量,在编译器就可以解析 
        * */ 
        final String str8 = "b"; 
        String str9 = "a" + str8; 
        String str89 = "ab"; 
        System.out.println("str9 == str87: " + (str9 == str89)); //true 
    } 

} 

String 的两个成员变量:

由于 String 存储的其实是 utf-16 编码格式的字符 Character,因此可以支持对多种编码的转换,也就出现了getBytes(String charsetName)等方法,可以方便的进行字符串的字符集转换。

总结

  • String可以用来进行字符集的转换Character是有Unicode的实现的,因此一个char16bit而不是****8bit。目前能用的范围是U+0000到U+10FFFF。
  • 在比较String对象的时候,一定注意常量池带来的影响
  • String是不可变对象,所以对String的改变都可能需要重新创建底层的数组,然后在拷贝之前的内容。

6.OOP Notes

  • **协变返回类型(covariant return type)是指:子类在重写父类的方法时,其返回类型可以是父类方法返回类型的子类型。 **

  • 访问修饰符的访问级别的使用遵从最小访问原则:总是使用满足要求的最弱的访问级别。

  • 属于对象的变量称为实例变量(instance variables),属于类的变量则为静态字段或者类变量。类的所有实例共享静态变量,静态变量在内存中的一个固定的位置。此外,类还可以有静态方法(static method or class variable),与之相对的是实例方法(instance method)。实例方法可以访问实例变量和其他实例方法,并且可以访问静态变量和静态方法。而静态方法只能访问静态变量和静态方法,不能访问实例变量和实例方法。

  • static 和 final 组合起来可以定义常量(constant)。如果常量的类型为基本类型或者 String,那么编译器将对这些常量进行直接替换,称为编译时常量(compile time constant)。

  • 静态初始化块在加载类以后,生成 Class 对象时执行。一个类可以有任意数量的静态初始化块,执行的顺序为各个静态初始化块定义的顺序。

    static { 
        // whatever code is needed for initialization goes here 
    } 
    

    替代方式是用静态方法来代替,可以重复利用初始化的代码:

    class Whatever { 
        public static varType myVar = initializeClassVariable(); 
             
        private static varType initializeClassVariable() { 
    
            // initialization code goes here  
        } 
    }
    

    对于实例,可以在构造函数中进行初始化,也可以定义初始化块和 final 方法。

    { 
        // whatever code is needed for initialization goes here 
    }
    

    Java 编译器将会复制初始化块到每一个构造函数。此外代替的方式是使用 final 方法:

    class Whatever { 
        private varType myVar = initializeInstanceVariable(); 
             
        protected final varType initializeInstanceVariable() { 
    
             // initialization code goes here 
        } 
    }
    

    注意必须使用 final 方法,否则将可能造成问题。

    这一条可以参考 Effective Java 中的:决不在构造器内调用可能被覆盖的函数,无论是直接调用还是间接调用,这样是错误的!使用 final 可以避免子类重写覆盖。因为在构造器中使用子类重写的函数,其中的某些变量还没有初始化。

  • Java 允许在一个类的内部定义另外一个类,在某个类内部定义的类称为嵌套类。嵌套类根据是否是静态分为静态嵌套类(static nested class)和内部类(inner class)内部类可以访问外部类的成员,包括 private 修饰的成员。静态嵌套内则不能访问外部内的成员。嵌套类本质上是外部类的成员,嵌套类可以声明为 private、public、protected 和 package private。

    内部类的实例对象必须依附于外部类的实例,但静态类的对象可独立创建

    使用嵌套类的原因:

    • 将只在一个地方使用的类放在一起,在逻辑上是合理。如果一个类仅对某个类有用,那么将该类放入使用类之中是合理。
    • 使用内部类有助于封装。
    • 有助于提高可读性和维护性。

    静态嵌套类与其他 top-level 类相似,只能通过外部类的实例去访问外部类的成员。

    In effect, a static nested class is behaviorally a top-level class that has been nested in another top-level class for packaging convenience.

    OuterClass.StaticNestedClass nestedObject = 
         new OuterClass.StaticNestedClass(); 
    

    内部类能够直接访问外部内的成员和函数,因为内部类持有外部类实例的一个引用。又因为内部类与外部类的一个实例相关联,内部类不能够定义任何的静态成员(static member),但是允许定义静态常量

    OuterClass.InnerClass innerObject = outerObject.new InnerClass(); 
    

    还有两种典型的内部类:局部类(local classes)和匿名类(anonymous classes)

  • 局部类(Local classes)是指定义在块(block)中的类,通常定义在某个方法内部。局部类可以访问外部类的成员,此外还可以访问块内的声明为final局部变量当局部类访问一个final局部变量或者块内的final参数,称为局部类捕获(capture)了该变量或参数。JDK8以后,还可以访问事实不可变(effectively final的局部变量和参数,和Lambda类似。事实不可变是指变量在初始化以后,变量的值不会改变。与内部类相似,局部类也不能定义static字段和方法,如果局部类定义在静态方法之中,那么局部类则只能访问外部类的静态成员和final局部变量以及参数。

    public void sayGoodbyeInEnglish() { 
        class EnglishGoodbye { 
            public static final String farewell = "Bye bye"; 
            public void sayGoodbye() { 
                System.out.println(farewell); 
            } 
        } 
        EnglishGoodbye myEnglishGoodbye = new EnglishGoodbye(); 
        myEnglishGoodbye.sayGoodbye(); 
    } 
    
  • interface本质上是static的,因此在接口中的内部类和局部类中不能定义静态方法,也不能定义****interface

  • 匿名类是没有名字的局部类,如果只使用某个类一次,就可以使用匿名类。在语法形式上,定义局部类是声明,而匿名类则是一个表达式(会返回实例)。

    • An anonymous class has access to the members of its enclosing class.
    • An anonymous class cannot access local variables in its enclosing scope that are not declared as final or effectively final.
    • Like a nested class, a declaration of a type (such as a variable) in an anonymous class shadows any other declarations in the enclosing scope that have the same name.

    对于静态成员的限制:

    • You cannot declare static initializers or member interfaces in an anonymous class.
    • An anonymous class can have static members provided that they are constant variables.

    在匿名类中可以定义:

    • Fields
    • Extra methods (even if they do not implement any methods of the supertype)
    • Instance initializers
    • Local classes

    但是不能定义任何构造函数。

  • Lambda表达式与内部类和局部类不同,并没有变量屏蔽的问题。Lambda表达式是词法范围的,Lambda并不引入新一级的Scope,因此Lambda中声明的变量就是外部Scope中的变量

    void methodInFirstLevel(int x) { 
    
        // The following statement causes the compiler to generate 
        // the error "local variables referenced from a lambda expression 
        // must be final or effectively final" in statement A: 
        // x = 99; 
        Consumer<Integer> myConsumer = (y) ->  
        { 
            System.out.println("x = " + x); // Statement A 
            System.out.println("y = " + y); 
            System.out.println("this.x = " + this.x); 
            System.out.println("LambdaScopeTest.this.x = " + 
                               LambdaScopeTest.this.x); 
        }; 
    
        myConsumer.accept(x); 
    
    } 
    
  • Lambda表达式的类型由目标类型(target type)和Lambda所处的上下文环境决定。Java编译器可以在下面的情况中确定Lambda表达式的类型:变量声明,赋值,返回语句,数组初始化,方法或者构造函数参数,Lambda表达体,条件语句和Cast表达式。

  • 方法引用(method reference):

  • 接口是软件对象之间的协议(interfaces are contracts)。Java中,接口是一种引用类型,仅包含常量,方法签名,默认方法,静态方法和嵌套类型。接口不能被实例化,只能被实现或者被其他接口继承。接口可以拓展一个或者多个父接口,但类只能继承一个父类。

  • 接口内部可以包含抽象方法默认方法静态方法。默认方法通过defualt关键词进行定义。所有的方法都是默认public的,可以省略。接口中定义的常量都是public static final的。defualt****方法主要用途是为存在的接口添加新的功能,并且能够维持向后的兼容性

  • 如果需要为接口增加新的方法,为了不影响之前实现了该接口的类,有三种选择:

    • 定义一个新接口,并拓展之前的接口

      public interface DoItPlus extends DoIt { 
          boolean didItWork(int i, double x, String s); 
      } 
      
    • 定义默认方法

      public interface DoIt { 
          void doSomething(int i, double x); 
          int doSomethingElse(String s); 
          default boolean didItWork(int i, double x, String s) { 
              // Method body  
          } 
      } 
      
    • 定义新的静态方法

  • 扩展包含default 方法的接口时,可以:

    • 直接继承父接口的default方法
    • 重新声明default方法,使得其为abstract的
    • 重写default方法
  • 子类继承父类的所有的public和protected成员。如果子类和父类在同一个包下,那么子类也会继承父类中的package-private成员。子类并不继承父类的private成员。嵌套类可以访问外部类的所有成员(包含private),因此如果一个public或者protected的嵌套类被子类继承,那么嵌套类的子类也可以访问所有私有的父类成员

    对于子类继承来的成员,可以替换,隐藏和补充新的方法:

    • 可以在子类中声明一个与父类名字相同的字段,这样可以隐藏父类的字段,但不推荐。对于static方法,如果子类中存在同名的static方法,这样也将隐藏父类的字段
    • 子类可以重写继承来的方法
    • 子类在构造函数中可以使用super来调用父类的构造函数。
  • Java不允许继承多个类的一个原因是,对于一个继承了多个父类的类,并且父类中存在同名的字段,那么子类中的字段应该来自于哪一个父类呢?以及各个父类中的构造方法的调用顺序等。。(For example, suppose that you are able to define a new class that extends multiple classes. When you create an object by instantiating that class, that object will inherit fields from all of the class's superclasses. What if methods or constructors from different superclasses instantiate the same field? Which method or constructor will take precedence? Because interfaces do not contain fields, you do not have to worry about problems that result from multiple inheritance of state.)

  • 隐藏(hiding)一个静态方法和重写一个实例方法的不同:

    • 对于子类对象调用重写的实例方法总是子类的实例方法被执行(多态)
    • 类调用隐藏的static方法时,被执行的static方法取决于对象的引用类型,如果是子类的引用,那么调用子类的static方法,如果是父类,则调用父类的static方法(属于覆盖,等同重载)
  • 对于重写方法的访问修饰符只可以放宽,不能减少

7.Annotation

8.Generics

9.Basic I/O

10.NIO

11.Proxy

参见我的另外一篇博客:Java 设计模式:代理模式。

12.其它

标签:lang,Java,String,子类,枚举,实例,方法,final
From: https://www.cnblogs.com/meyok/p/16949038.html

相关文章

  • Java实现MySQL binlog日志监听
    使用案例引入maven依赖<dependency><groupId>com.github.shyiko</groupId><artifactId>mysql-binlog-connector-java</artifactId><version>0.21.0</version></......
  • Java8中Collectors求和功能的自定义扩展
    业务中需要将一组数据分类后收集总和,原本可以使用Collectors.summingInt(),但是我们的数据源是BigDecimal类型的,而Java8原生只提供了summingInt、summingLong、summingDouble......
  • java二维数组
    本文介绍java中二维数组的存放位置int[][]arr=newint[2][3];jvm存放二维数组的图示:下面介绍列数不明确的情况: 代码如下:publicclassTwo{publicsta......
  • [Javascript Performance] Optimisation and deoptimization
    Theoptimizingcompileroptimizesforwhatit’sseen.Ifitseessomethingnew,that’sproblematic. Seletingpropertieshassomestrangeimplicationsonpe......
  • [Javascript Performance] How to benchmark code performance
    Code:benchmark.jsconst{performance}=require('perf_hooks');//SETUP......
  • Jenkins+GitLab实现构建JAVA代码
    目录一、前置环境配置二、创建一个maven任务需要提前部署完成Jenkins+GitLab+maven可以参考我的其他文章进行部署一、前置环境配置1、安装MavenIntegration插件Jenki......
  • java中== 和equals的区别
    本文主要介绍==和equals的区别1.==比较的是地址,引用类型(除了String类)的时候,只要不是同一个对象,就不是同一个地址,String类型的时候,如果new出来两个对象,那么也是不同地......
  • Java火焰图简单学习
    前言立的flags倒了太多次自己还是太菜了..课题太大,自己简单总结一下.要是自己总结错了.就不收费,错就错了!-_-!第一步准备环境一定要设置对java的HOME以及PAT......
  • ( Java 和 C++ 还是有差别)卑微地向API低下了头,但是反转字符串的单词依旧写了很久 学
    344.反转字符串-ezclassSolution{publicvoidreverseString(char[]s){intleft=0,right=s.length-1;chartmp;while(l......
  • 泛型—JAVA基础学习
    泛型泛型的简单了解为什么引入泛型?泛型可以视为编写代码时的语法检查这里可以通过一个简单的例子来看当不使用泛型时:classStove{ publicstaticObjectheat(Obj......