Java快速上手开发学习笔记

782 阅读9分钟

开发工具

IDEA 代码规范阿里p3c插件安装

Java基础

数据类型

装箱和拆箱

  • 装箱:基本数据类型转换为包装器类型,比如将int类型转换为Interger类型。
  • 拆箱:包装器类型转化为基本数据类型,比如将Interger类型转换为int类型。
基础类型 包装类
  • Integer派别:IntegerShortByteCharacterLong这几个类的valueOf方法的实现是类似的。
  • Double派别:DoubleFloatvalueOf方法的实现是类似的。每次都返回不同的对象。
1.当一个基础数据类型与封装类进行==、+、-、*、/运算时,会将封装类进行拆箱,对基础数据类型进行运算。

2.装箱操作会创建对象,频繁的装箱操作会消耗许多内存,影响性能,所以可以避免装箱的时候应该尽量避免。

3.equals(Object o) 因为原equals方法中的参数类型是封装类型,所传入的参数类型(a)是原始数据类型,所以会自动对其装箱,反之,会对其进行拆箱。

4.当两种不同类型用==比较时,包装器类的需要拆箱,当同种类型用==比较时,会自动拆箱或者装箱。 

数组

  • 数组是用于存储同样数据类型的多个数据的一种数据结构。
  • 数组长度不可变。
  • 数组本身是一种引用类型。

数组定义

type[] arrayName;(推荐)
type arrayName[];

数组初始化

静态初始化:arrayName = new type[]{element1, element2, ......};
动态初始化:arrayName = new type[length];
可以使用foreach循环来遍历数组。

String类

  • Java中的String类首字母必须大写,因为它是一个类而不是一个内部的类型。
  • String类中存储字符仍然使用的是char类型的数组。
  • String类被final关键字修饰,意味着String类不能被继承,并且它的成员方法都默认为final方法;字符串一旦创建就不能再修改。
  • String类定义的字符串为字符串常量,是不可变的。Java会使用一个常量池机制存储字符串。
  • 如果要使用字符串变量,请使用StringBuilder或者StringBuffer
  • 可以使用+连接符来连接两个字符串。
  • 使用+连接符时,JVM会隐式创建StringBuilder对象,这种方式在大部分情况下并不会造成效率的损失,不过在进行大量循环拼接字符串时则需要注意。

面相对象

  • 修饰符 class
    class 类名 {    }
    
  • 定义成员变量
    【修饰符】 类型  变量名 【= 默认值】
    
  • 定义方法
    【修饰符】 返回值类型  方法名(形参列表){    }
    

访问控制

  • 是一个类似文件夹的结构,用来避免类的重名,同一包下的类代表同一个逻辑下的类库单元。
  • 在类的第一行中添加package packageName来定义一个类属于哪个包。
  • Java中,使用import语句来动态引入一个你需要使用的Java包。
  • 使用import static语句来导入指定类的静态成员变量、静态方法。
一个.java文件中可以有很多类。不过注意以下几点:
1、public 权限的类只能有一个(也可以一个都没有,但最多只有1个)
2、这个.java文件的文件名必须是public类的类名(一般的情况下,这里放置main方法是程序的入口。)
3、若这个文件中没有public的类,则文件名随便是一个类的名字即可
4、用javac 编译这个.java文件的时候,它会给每一个类生成一个.class文件

继承

  • Java使用extends关键字来实现继承。
  • Java使用implements来实现一个接口。
  • Java中,只可以继承一个父类。
  • 子类可以重写父类的方法。Java中需要在子类中的重写方法上使用@Override注解。子类使用super()方法调用父类的方法,包括构造方法。
  • 修饰类当用final去修饰一个类的时候,表示这个类不能被继承:
    • final修饰的类,final类中的成员变量可以根据自己的实际需要设计为fianl
    • final类中的成员方法都会被隐式的指定为final方法。在类的第一行中添加package packageName来定义一个类属于哪个包。
  • final修饰的方法不能被重写:
    • 一个类的private方法会隐式的被指定为final方法。
    • 如果父类中有final修饰的方法,那么子类不能去重写。
  • 修饰成员变量:
    • 必须初始化值。
    • fianl修饰的成员变量赋值,有两种方式:
      • 直接赋值
      • 全部在构造方法中赋初值。
    • 如果修饰的成员变量是基本类型,则表示这个变量的值不能改变。
    • 如果修饰的成员变量是一个引用类型,则是说这个引用的地址的值不能修改,但是这个引用所指向的对象里面的内容还是可以改变的。
  • 修饰局部变量:
    • 必须要赋初始值,而且是只能初始化一次。
    • 即为常量,不可修改。

抽象类

  • 抽象类定义的格式:
    abstract class 类名{    }
    
  • 抽象方法定义格式:
    public abstract 返回值类型 方法名(参数);
    
  • 抽象类和抽象方法都要被abstract修饰,抽象方法一定要定义在抽象类中。
  • 抽象类不可以直接创建对象。
  • 只有覆盖了抽象类中所有的抽象方法后,其子类才可以创建对象。否则该子类还是一个抽象类。

接口

  • 接口是隐式抽象的,当声明一个接口的时候,不必使用abstract关键字。
  • 接口中每一个方法也是隐式抽象的,声明时同样不需要abstract关键字。
  • 接口中的方法都是公有的。
  • 编译时自动为接口里定义的方法添加public abstract修饰符。
  • Java接口里的成员变量只能是public static final共同修饰的,并且必须赋初始值,可以不写public static final,编译的时候会自动添加。

泛型 [参考]

泛型,即“参数化类型”。就是将类型由原来的具体的类型参数化,类似于方法中的变量参数,此时类型也定义成参数形式(可以称之为类型形参),然后在使用/调用时传入具体的类型(类型实参)。

一些常用的泛型类型变量:
E:元素(Element),多用于java集合框架
K:关键字(Key)
N:数字(Number)
T:类型(Type)
V:值(Value)

使用泛型的意义

  • 适用于多种数据类型执行相同的代码(代码复用)

  • 泛型中的类型在使用时指定,不需要强制类型转换(类型安全,编译器会检查类型)

泛型类

定义一个泛型类:public class GenericClass<T>{}

public class GenericClass<T> {
    private T data;

    public T getData() {
        return data;
    }

    public void setData(T data) {
        this.data = data;
    }

    public static void main(String[] args) {
        GenericClass<String> genericClass=new GenericClass<>();
        genericClass.setData("Generic Class");
        System.out.println(genericClass.getData());
    }
}

泛型接口

定义一个泛型接口:public interface GenericIntercace<T>{}

public interface GenericIntercace<T> {
     T getData();
}

实现泛型接口方式一:public class ImplGenericInterface1<T> implements GenericIntercace<T>

public class ImplGenericInterface1<T> implements GenericIntercace<T> {
    private T data;

    private void setData(T data) {
        this.data = data;
    }

    @Override
    public T getData() {
        return data;
    }

    public static void main(String[] args) {
        ImplGenericInterface1<String> implGenericInterface1 = new ImplGenericInterface1<>();
        implGenericInterface1.setData("Generic Interface1");
        System.out.println(implGenericInterface1.getData());
    }
}

实现泛型接口方式二:public class ImplGenericInterface2 implements GenericIntercace<String> {}

public class ImplGenericInterface2 implements GenericIntercace<String> {
    @Override
    public String getData() {
        return "Generic Interface2";
    }

    public static void main(String[] args) {
        ImplGenericInterface2 implGenericInterface2 = new ImplGenericInterface2();
        System.out.println(implGenericInterface2.getData());
    }
}
  • 1.对于泛型参数是继承关系的泛型类之间是没有继承关系的
  • 2.泛型类可以继承其它泛型类,例如: public class ArrayList extends AbstractList
  • 3.泛型类的继承关系在使用中同样会受到泛型类型的影响

定义一个泛型方法

private static<T> TgenericAdd(T a, T b) {}

通配符类型

  • <? extends Parent> 指定了泛型类型的上届

    /**
    * <? extend Parent> 指定了泛型类型的上界
    */
    public static void printExtends(GenericClass<? extends Fruit> genericClass){
        System.out.println(genericClass.getData().getColor());
    }
    
    • ? extends X 表示类型的上界,类型参数是X的子类,那么可以肯定的说,get方法返回的一定是个X(不管是X或者X的子类)编译器是可以确定知道的。但是set方法只知道传入的是个X,至于具体是X的那个子类,不知道。
    • 总结:主要用于安全地访问数据,可以访问X及其子类型,并且不能写入非null的数据。
  • <? super Child> 指定了泛型类型的下届

    /**
    * <? super Child> 指定了泛型类型的下界
    */
    public static void printSuper(GenericClass<? super Apple> genericClass){
        System.out.println(genericClass.getData());
    }
    
    • ? super X 表示类型的下界,类型参数是X的超类(包括X本身),那么可以肯定的说,get方法返回的一定是个X的超类,那么到底是哪个超类?不知道,但是可以肯定的说,Object一定是它的超类,所以get方法返回Object。对于set方法来说,编译器不知道它需要的确切类型,但是X和X的子类可以安全的转型为X。
    • 总结:主要用于安全地写入数据,可以写入X及其子类型。
  • <?> 指定了没有限制的泛型类型

    /**
    * <?> 指定了没有限定的通配符
    */
    public static void printNonLimit(GenericClass<?> genericClass){
        System.out.println(genericClass.getData());
    }
    

Java lambda表达式

Java lambda表达式主要作用是代替匿名内部类的繁琐语法。由三部分组成:

  • 输入:->前面的部分,即被()包围的部分。此处只有一个输入参数,实际上输入是可以有多个的,如两个参数时写法:(a, b);当然也可以没有输入,此时直接就可以是()。
  • 函数体:->后面的部分,即被{}包围的部分;可以是一段代码。
  • 输出:函数式编程可以没有返回值,也可以有返回值。如果有返回值时,需要代码段的最后一句通过return的方式返回对应的值。
Consumer c = (o)->{
    System.out.println(o);
}

Java 的lambda表达式使用的是一种叫做函数式接口的东西,函数式接口需要满足两个条件:

  1. 使用@FunctionalInterface注解修饰。
  2. 接口中智能包含一个方法。(default方法和static方法除外) 例如:
@FunctionalInterface
interface A {
void abc();
default void def(){
......
}

如果lambda表达式的代码块只有一条代码,则可以使用方法引用和构造器引用。

  • 方法引用: 如果我们要实现接口的方法与另一个方法A类似,(这里的类似是指参数类型与返回值部分相同),我们直接声明A方法即可。也就是,不再使用lambda表达式的标准形式,改用高级形式。无论是标准形式还是高级形式,都是lambda表达式的一种表现形式。
  • 方法引用的语法: 对象::实例方法类::静态方法类::实例方法 Compare c = String::equals;

构造引用:构造引用的语法:类名::new

集合

Stream流

常用工具类/方法

Java并发与多线程

Java原理与调优

Spring与SpringMVC

SpringBoot实践

未完待续...