Java基本语法知识点

1、字符和字符串

  1. 字符类型
    因为Java在内存中总是使用Unicode表示字符,所以,一个英文字符和一个中文字符都用一个char类型表示,它们都占用两个字节(16bit)。
    要显示一个字符的Unicode编码,只需将char类型直接赋值给int类型即可。
    还可以直接用转义字符\u+Unicode编码来表示一个字符。
    char c3 = '\u0041'; // 'A',因为十六进制0041 = 十进制65
    char c4 = '\u4e2d'; // '中',因为十六进制4e2d = 十进制20013
    
    char和int之间的相互转换
    char转int:
    强制类型转换会把char按照ascii码转换为对应的int
    使用已有方法Character.getNumericValue(a)
    int转char
    强制类型转换会把int按照ascii码转换为对应的字符
    先转为String,然后转为char[],最后转为char。
  2. 字符串类型
    Java的String类型在内存中也是以Unicode码存在的。
    Java的字符串是一个引用类型(指针),且字符串的内容不可变。但是可以修改引用类型的指向。
    注意要区分空值null和空字符串"",空字符串是一个有效的字符串对象,它不等于null。
    String转int:
    Integer.parseInt(str)
    Integer.valueOf(str).intValue()
    int转String:
    num + ""
    String.valueOf(num)
    Integer.toString(num)

2、数组类型

  1. 数组的特性
    数组所有元素初始化为默认值,整型都是0,浮点型是0.0,布尔型是false
    数组一旦创建后,大小就不可改变。
    可以直接初始化数组而不明确指定其长度,其长度由编译器自动推算。
    字符串数组:字符串是引用类型,定义一个长度为N的字符串数组,其每个元素都指向某个字符串对象,字符串对象的内容不可修改,但是字符串数组的指向可以修改。
  2. 数组排序
    Arrays.sort会改变数组本身。
    Arrays.sort修改引用类型的数组时,修改的是数组中引用类型的指向。

3、流程控制

  1. if判断
    浮点数在计算机中常常无法精确表示,并且计算可能出现误差,因此,判断浮点数相等用==判断不靠谱。正确的方法是利用差值小于某个临界值来判断。
    引用类型判断内容相等要使用equals(),注意避免NullPointerException
    Math.abs(x - 0.1) < 0.00001
    注意:执行语句s1.equals(s2)时,如果变量s1为null,会报NullPointerException,要避免NullPointerException错误,可以利用短路运算符&&
    if (s1 != null && s1.equals("hello")) {
        System.out.println("hello");
    }
    
  2. for循环
    使用for循环时,计数器变量i要尽量定义在for循环中,这样符合访问范围缩到最小的原则。

4、面向对象基础

  1. 方法
    在方法内部,可以使用一个隐含的变量this,它始终指向当前实例。
    如果没有命名冲突,可以省略this。
    但是,如果有局部变量和字段重名,那么局部变量优先级更高,就必须加上this。
    可变参数相当于数组类型:
    public void setNames(String... names) {
        this.names = names;
    }
    
    此接口可以传入0-N个Sting参数,接口内部names可作为数组处理。
    当方法的入参是引用类型时,调用方的变量,和接收方的参数变量,指向的是同一个对象。双方任意一方对这个对象的修改,都会影响对方。
  2. 构造方法
    在java中创建实例对象时,按照如下顺序进行初始化:
    (1)先初始化字段
    (2)再执行构造方法初始化
    (3)每个类都默认存在一个入参我空的构造方法
  3. 继承
    因为所有的class最终都继承自ObjectObject没有父类。
    继承有个特点,就是子类无法访问父类的private字段或者private方法。
    protected修饰的字段可以被子类访问,protected关键字可以把字段和方法的访问权限控制在继承树内部,一个protected字段和方法可以被其子类,以及子类的子类所访问。
    super关键字表示父类(超类)。
    在Java中,任何class的构造方法,第一行语句必须是调用父类的构造方法。如果没有明确地调用父类的构造方法,编译器会帮我们自动加一句super();,如果父类没有默认的构造方法(入参为空的构造方法),子类就必须显式调用super()并给出参数以便让编译器定位到父类的一个合适的构造方法。
    即子类不会继承任何父类的构造方法。子类默认的构造方法是编译器自动生成的,不是继承的。
    把一个子类类型安全地变为父类类型的赋值,被称为向上转型(upcasting),向上转型实际上是把一个子类型安全地变为更加抽象的父类型。
    如果把一个父类类型强制转型为子类类型,就是向下转型(downcasting)。
    为了避免向下转型出错,Java提供了instanceof操作符,可以先判断一个实例究竟是不是某种类型。
  4. 多态
    在继承关系中,子类如果定义了一个与父类方法签名完全相同的方法(入参、方法名、返回值均相同),被称为覆写(Override)。
    加上@Override可以让编译器帮助检查是否进行了正确的覆写,但是@Override不是必需的。
    多态是指,针对某个类型的方法调用,其真正执行的方法取决于运行时期实际类型的方法。多态的例子
    在子类的覆写方法中,如果要调用父类的被覆写的方法,可以通过super来调用。
    继承可以允许子类覆写父类的方法。如果一个父类不允许子类对它的某个方法进行覆写,可以把该方法标记为final。用final修饰的方法不能被Override。
    如果一个类不希望任何其他类继承自它,那么可以把这个类本身标记为final。用final修饰的类不能被继承。
    对于一个类的实例字段,同样可以用final修饰。用final修饰的字段在初始化后不能被修改。
  5. 抽象类
    如果一个class定义了方法,但没有具体执行代码,这个方法就是抽象方法,抽象方法用abstract修饰,因为无法执行抽象方法,因此这个类也必须使用abstract修饰为抽象类。
    抽象类的作用:抽象类本身被设计成只能用于被继承,因此,抽象类可以强迫子类实现其定义的抽象方法,否则编译会报错。因此,抽象方法实际上相当于定义了“规范”。
  6. 抽象类
    如果一个抽象类没有字段,所有方法全部都是抽象方法:
    abstract class Person {
        public abstract void run();
        public abstract String getName();
    }
    
    就可以把该抽象类改写为接口:interface
    interface Person {
        void run();
        String getName();
    }
    
    所谓interface,就是比抽象类还要抽象的纯抽象接口,因为它连字段都不能有
    当一个具体的class去实现一个interface时,需要使用implements关键字。
    在Java中,一个类只能继承自另一个类,不能从多个类继承。但是,一个类可以实现多个interface
    一个interface可以继承自另一个interfaceinterface继承自interface使用extends,它相当于扩展了接口的方法。
    default方法:实现类可以不必覆写default方法。default方法的目的是,当我们需要给接口新增一个方法时,会涉及到修改全部子类。如果新增的是default方法,那么子类就不必全部修改,只需要在需要覆写的地方去覆写新增方法。
  7. 静态字段和静态方法
    class有一种字段,是用static修饰的字段,称为静态字段:static field。
    实例字段在每个实例中都有自己的一个独立“空间”,但是静态字段只有一个共享“空间”,所有实例都会共享该字段
    静态字段不属于实例,虽然可以用实例访问,但是其实他们都指向class的静态字段,因此不推荐用实例变量.静态字段,因为在java中实例对象并没有静态字段。
    用static修饰的方法称为静态方法
    调用实例方法必须通过一个实例变量,而调用静态方法则不需要实例变量,通过类名就可以调用。
    因为静态方法属于class而不属于实例,因此,静态方法内部,无法访问this变量,也无法访问实例字段,它只能访问静态字段。
    因为interface是一个纯抽象类,所以它不能定义实例字段。但是,interface是可以有静态字段的,并且静态字段必须为final类型。
    实际上,因为interface的字段只能是public static final类型,所以我们可以把这些修饰符都去掉。

  8. 编写class的时候,编译器会自动帮我们做两个import动作:
    (1)默认自动import当前package的其他class;
    (2)默认自动import java.lang.*。
    包没有父子关系,com.apachecom.apache.abc是不同的包。
    一个.java文件只能包含一个public类,但可以包含多个非public类。如果有public类,文件名必须和public类的名字相同。
    如果不确定是否需要public,就不声明为public,即尽可能少地暴露对外的字段和方法。
  9. Java核心类
    包装类型 :
    因为包装类型非常有用,Java核心库为每种基本类型都提供了对应的包装类型。
    基本类型 对应的引用类型
    boolean java.lang.Boolean
    int java.lang.Integer
    所有的包装类型都是不变类,Integer的核心源码如下:
    public final class Integer {
        private final int value;
    }
    
    包装类需要用equals()比较是否相同。
    每种包装类均提供了大量的方法,可以自行查询使用。
    在Java中,并没有无符号整型(Unsigned)的基本数据类型。byte、short、int和long都是带符号整型,最高位是符号位。
  10. JavaBean
    在Java中,有很多class的定义都符合这样的规范:
    (1)若干private实例字段;
    (2)通过public方法来读写实例字段。
    如果class的读写方法都符合以下的命名规范:
    // 读方法:
    public Type getXyz()
    // 写方法:
    public void setXyz(Type value)
    
    那么这种class被称为JavaBean。
    boolean字段比较特殊,它的读方法一般命名为isXyz()
    JavaBean主要用来传递数据,即把一组数据组合成一个JavaBean便于传输。此外,JavaBean可以方便地被IDE工具分析,生成读写属性的代码,主要用在图形界面的可视化设计中。
  11. 枚举类
    enum Weekday {
        SUN, MON, TUE, WED, THU, FRI, SAT;
    }
    
    枚举类的常用方法,随用随查即可。
  12. BigInteger
    在Java中,由CPU原生提供的整型最大范围是64位long型整数。使用long型整数可以直接通过CPU指令进行计算,速度非常快。
    如果我们使用的整数范围超过了long型怎么办?这个时候,就只能用软件来模拟一个大整数。java.math.BigInteger就是用来表示任意大小的整数。BigInteger内部用一个int[]数组来模拟一个非常大的整数。
    对BigInteger做运算的时候,只能使用实例方法。
    和long型整数运算比,BigInteger不会有范围限制,但缺点是速度比较慢。
  13. BigDecimal
    和BigInteger类似,BigDecimal可以表示一个任意大小且精度完全准确的浮点数。
  14. 常用工具类
    (1)Math
    (2)Random
    Random用来创建伪随机数。所谓伪随机数,是指只要给定一个初始的种子,产生的随机数序列是完全一样的。
    (3)SecureRandom
    有伪随机数,就有真随机数。实际上真正的真随机数只能通过量子力学原理来获取,而我们想要的是一个不可预测的安全的随机数,SecureRandom就是用来创建安全的随机数的。

5、异常处理

  1. Java的异常
    Java异常继承关系
    Java异常继承关系
    Throwable有两个体系:Error和Exception,Error表示严重的错误,程序对此一般无能为力;而Exception则是运行时的错误,它可以被捕获并处理。
    Java规定:
    (1)必须捕获的异常,包括Exception及其子类,但不包括RuntimeException及其子类,这种类型的异常称为Checked Exception,如果不捕获就会出现编译失败。
    (2)不需要捕获的异常,包括Error及其子类,RuntimeException及其子类。
    在方法定义的时候,使用throws Xxx表示该方法可能抛出的异常类型。调用方在调用的时候,必须强制捕获这些异常,否则编译器会报错。

  2. 捕获异常
    在Java中,凡是可能抛出异常的语句,都可以用try … catch捕获。

  3. 抛出异常
    当某个方法抛出了异常时,如果当前方法没有捕获异常,异常就会被抛到上层调用方法,直到遇到某个try … catch被捕获为止。
    通过printStackTrace()可以打印出方法的调用栈。

    public class Main {
        public static void main(String[] args) {
            try {
                process1();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
        static void process1() {
            process2();
        }
    
        static void process2() {
            Integer.parseInt(null); // 会抛出NumberFormatException
        }
    }
    
  4. 自定义异常

  5. 使用断言
    Java断言的特点是:断言失败时会抛出AssertionError,导致程序结束退出。因此,断言不能用于可恢复的程序错误,只应该用于开发和测试阶段

    public static void main(String[] args) {
        double x = Math.abs(-123.45);
        assert x >= 0 : "x must >= 0";
        System.out.println(x);
    }
    

    语句assert x >= 0;即为断言,断言条件x >= 0预期为true。如果计算结果为false,则断言失败,抛出AssertionError,并带上消息x must >= 0,更加便于调试。
    JVM默认关闭断言指令,要执行assert语句,必须给Java虚拟机传递-enableassertions(可简写为-ea)参数启用断言。

  6. 使用JDK Logging
    Java标准库内置了日志包java.util.logging,但是有以下局限性:
    (1)Logging系统在JVM启动时读取配置文件并完成初始化,一旦开始运行main()方法,就无法修改配置;
    (2)配置不太方便,需要在JVM启动时传递参数-Djava.util.logging.config.file=。
    因此,Java标准库内置的Logging使用并不是非常广泛。

  7. 使用Commons Logging
    Commons Logging的特色是,它可以挂接不同的日志系统,并通过配置文件指定挂接的日志系统。默认情况下,Commons Loggin自动搜索并使用Log4j(Log4j是另一个流行的日志系统),如果没有找到Log4j,再使用JDK Logging。

  8. 使用Log4j
    Log4j是一个组件化设计的日志系统,它的架构大致如下:
    Log4j架构
    Log4j自动通过不同的Appender把同一条日志输出到不同的目的地:
    console:输出到屏幕;
    file:输出到文件;
    socket:通过网络输出到远程计算机;
    jdbc:输出到数据库。

    我们在实际使用的时候,并不需要关心Log4j的API,而是通过配置文件来配置它,以XML配置为例,使用Log4j的时候,我们把一个log4j2.xml的文件放到classpath下就可以让Log4j读取配置文件并按照我们的配置来输出日志。
    Commons Logging和Log4j,一个负责充当日志API,一个负责实现日志底层,搭配使用非常便于开发。

  9. 使用SLF4J和Logback
    SLF4J类似于Commons Logging,也是一个日志接口,而Logback类似于Log4j,是一个日志的实现。

6、反射

  1. Class类
    除了int等基本类型外,Java的其他类型全部都是class(包括interface)。
    class(包括interface)的本质是数据类型(Type),无继承关系的数据类型无法赋值。
    class是由JVM在执行过程中动态加载的。JVM在第一次读取到一种class类型时,将其加载进内存。
    每加载一种class,JVM就为其创建一个Class类型的实例,并关联起来。
    注意:这里的Class类型是一个名叫Class的class。
    public final class Class {
        private Class() {}
     }
    
    这个Class实例是JVM内部创建的,JVM持有的每个Class实例都指向一个数据类型(class或interface),一个Class实例包含了该class的所有完整信息,因此,如果获取了某个Class实例,我们就可以通过这个Class实例获取到该实例对应的class的所有信息。
    这种通过Class实例获取class信息的方法称为反射(Reflection)。
    如何获取一个class的Class实例?有三个方法:
    方法一:直接通过一个class的静态变量class获取:
     Class cls = String.class;
    
    方法二:如果我们有一个实例变量,可以通过该实例变量提供的getClass()方法获取:
    String s = "Hello";
    Class cls = s.getClass();
    
    方法三:如果知道一个class的完整类名,可以通过静态方法Class.forName()获取:
    Class cls = Class.forName("java.lang.String");
    
    因为Class实例在JVM中是唯一的,所以,上述方法获取的Class实例是同一个实例
  2. 访问字段
    Java的反射API提供的Field类封装了字段的所有信息。
    通过Class实例的方法可以获取Field实例:getField(),getFields(),getDeclaredField(),getDeclaredFields()。
    通过Field实例可以获取字段信息:getName(),getType(),getModifiers()。
  3. 调用方法
    Java的反射API提供的Method对象封装了方法的所有信息。
  4. 调用构造方法
    Constructor对象封装了构造方法的所有信息。
  5. 获取继承关系
    通过Class对象可以获取继承关系。
  6. 动态代理
    Java标准库提供了动态代理功能,允许在运行期动态创建一个接口的实例。

7、注解

  1. 使用注解
    第一类是由编译器使用的注解,例如:@Override:让编译器检查该方法是否正确地实现了覆写,这类注解不会被编译进入.class文件,它们在编译后就被编译器扔掉了。
    第二类是由工具处理.class文件使用的注解,比如有些工具会在加载class的时候,对class做动态修改,实现一些特殊的功能。这类注解会被编译进入.class文件,但加载结束后并不会存在于内存中。这类注解只被一些底层库使用,一般我们不必自己处理。
    第三类是在程序运行期能够读取的注解,它们在加载后一直存在于JVM中,这也是最常用的注解。
  2. 定义注解
  3. 处理注解

8、泛型

  1. 什么是泛型
    泛型就是定义一种模板,例如ArrayList<T>,然后在代码中为用到的类创建对应的ArrayList<类型>
    这样一来,既实现了编写一次,万能匹配,又通过编译器保证了类型安全:这就是泛型。
    在Java标准库中的ArrayList<T>实现了List<T>接口,它可以向上转型为List<T>
  2. 使用泛型
    使用泛型时,把泛型参数<T>替换为需要的class类型,例如:ArrayList<String>,ArrayList<Number>等。
    不指定泛型参数类型时,编译器会给出警告,且只能将<T>视为Object类型。
    可以在接口中定义泛型类型,实现此接口的类必须实现正确的泛型类型。
  3. extends通配符
  4. super通配符

9、集合

Java的集合类定义在java.util包中,支持泛型,主要提供了3种集合类,包括List,Set和Map。Java集合使用统一的Iterator遍历,尽量不要使用遗留接口。

10、IO

参考:

廖雪峰java教程

发布了16 篇原创文章 · 获赞 0 · 访问量 815

猜你喜欢

转载自blog.csdn.net/shengruxiahua2571/article/details/100523739