java基础笔记(一)

前一段时间有计划重看一下java基础的内容,只是各种事不断的打断,到现在过了一部分内容。刚开始有些基础的东西,把之前没有注意到的地方,进行一个简单的记录;

有些地方,还可以进一步深入,这里只做浅层的总览了,之后再针对性的深究,写点demo。

1.基本数据类型的默认值:

 public class DefaultValue {
	char a;
    boolean b;
    byte c;
    short d;
    int e;
    long f;
    float g;
    double h;
    public static void main(String[] args) {
        DefaultValue defaultValue = new DefaultValue();
        defaultValue.printJavaDataDefaultValue();
    }

    //打印java中8个基本数据类型的默认值
    public void printJavaDataDefaultValue() {
        System.out.println("**********打印java中8个基本数据类型的默认值**********");
        System.out.println("char  = " + a);
        System.out.println("a=='\\u0000'  = "+ (a=='\u0000'));
        System.out.println("boolean  = " + b);
        System.out.println("byte  = " + c);
        System.out.println("short = " + d);
        System.out.println("int  = " + e);
        System.out.println("long  = " + f);
        System.out.println("float = " + g);
        System.out.println("double = " + h);
    }
 }

输出:

打印java中8个基本数据类型的默认值
char =
a==’\u0000’ = true
boolean = false
byte = 0
short = 0
int = 0
long = 0
float = 0.0
double = 0.0

其中 char 的默认值是’\u0000’

2.引用的数组

引用数组声明的时候,只申请了引用的空间,具体对象还需要再次实例化;

Cat[] cats=new Cat[10];
cats[0]=new Cat();
//cat[1]为默认值null

3.java方法传值、传引用

方法的入参对于基本数据类型和字符串常量来说,传递的其实只是这个值本身的一个拷贝。对于外面的变量来说,并没有改变什么,入参的作用域也仅限函数内部,属于局部变量(包括包装类型和String)

对于数组、引用则存在如果在方法内对引用指向的内存内容修改,则外部也修改的问题。因为传递的是引用的拷贝,在方法内,拿到引用地址之后,如果修改引用变量的指向,则外部不变;如果修改指向地址的内容,则外部改变。

public class TestCat {
    public static void main(String[] args) {
        Cat c=new Cat();
        c.name="dudu";
        test1(c);
        System.out.println(c.name);
        test2(c);
        System.out.println(c.name);
    }

    public static void test1(Cat cat){
        cat=new Cat();//相当于修改局部变量cat的引用指向,不会对外部c的内容修改
        cat.name="test1";
    }
    public static void test2(Cat cat){
        cat.name="test2";//相当于对用一个引用指向的内容作了修改
    }

}

输出

dudu
test2

4.重载的参数匹配

对于一个普通的方法的调用,传参不一定要完全的类型匹配,实参可以自动类型转换成形参也是可以的。

比如一个方法fun(double price);

int a=10;

fun(a);

可以传递int类型的变量,自动类型转换。

当某个方法被重载,此时如果传参类型没有直接匹配项,重载会选择就“近”的进行调用。

当重载传参数引用,且引用类型没有完全匹配,则会根据继承关系,沿着参数当前类型,向下理。

顺带补充 重载的条件

1.函数名相同

2.参数个数不同或者参数类型不同

3.函数重载和返回值类型无关

5.构造方法

构造方法,在java中被编译成<init>方法,包括在类中,声明成员变量时,进行赋值,也会编译到该方法中。

然后是构造方法之间调用的一些注意事项

如下代码为例

public class Cat{
    private String name;
    private int age;
    //构造方法无返回值
    public Cat(String name){
        this.name=name;
    }
    public Cat(int age){
        this.age=age;
    }
    public Cat(int age,String name){
        this(name);
        //this(age); //调用重载的构造方法,必须是第一行,否则会报错。像这样,连着调用两个也不行。
        //this.age="dudu";//在调用重载构造方法时,不可以使用未初始化的成员变量,
        					
    }
    
}

1.构造方法里才能调用重载的构造方法;形式是this(参数列表),但必须是方法的第一行

2.构造方法不能调用自己,会死循环;

3.在调用重载的构造方法时,不可以使用成员变量。语义上讲,此时对象还没有初始化完成,处于中间状态;

4.构造方法无返回值。

6.静态方法

一些注意事项:

1.静态方法可以访问静态变量,包括自己类的静态变量,和可以访问的其他类的静态变量;

2.静态方法没有this自引用,不属于某个实例,调用的时候直接用类名调用,不能直接访问成员变量和成员方法;

但是可以通过传对象参数,或者新建对象,来获取成员变量。(根本原因:无自引用)

7.静态代码块

一些注意事项:

1.静态代码块中使用某个静态变量,必须在静态变量后面;(代码块中仅仅赋值是可以的 【少用】)

2.一个类中可以有多个静态代码块,但是,是有顺序的,相当于在编译的时候,会将多个代码块顺序组合在一起,组织到clinit(即class init)方法中。

8.Math类

1.一般情况下,调用的都是Math的静态方法,其构造函数是private。但是可以通过静态方法,来调用其构造函数来返回实例化对象。

2.Math.random(),实际是调用了Random类,实例化了对象,进行随机数生成。

Random类在java.util包中。在java.lang包中,不需要显示import,其他包需要显示导入。

Random中的nextInt(),返回值是int的整个值域,包括正负;

3.还有常用的Math.abs() ;Math.round()

BigInteger BigDecimal 大数 加减用大数类型封装好的函数 如add()

9.String类

1.String对象是不可变的,因为其存储字符的数据被private修饰,且不提供任何修改方法,所以一旦生成,内容不可修改。

2.虽然不是基本数据类型,但是允许直接=“dudu”,来进行对象的创建。可以不用使用new String(“dudu”)

3.toUpperCase() toLowerCase() 返回值是来修改字母大小写,但对象本身不变,是创建了新的对象。

4.charAt()

substring() 单参数是从哪里开始到最后; 双参数是从截取的下标,end不取。

toCharArray() 得到字符数组

split() 根据字符或者字符串进行分割

indexOf() 某个字符第一次出现的位置

lastIndexOf() 从最后找 第一次出现的位置

contains() 是否包括某子字符串

equals()

equalsIgnoreCase() 比较是否相等 忽略大小写

trim() 去掉字符串中的空格

10.StringBuilder

在java.lang包中

append(); 返回了自引用,所以可以直接多个拼接 str.append(" “).append(”–")

reverse();操作原对象

toString();返回新string对象

delete(a,b); a b是下标,取a不取b;

insert(a,"–"); 从下标a处开始插入;

11.重写

1.通过使用和父类方法签名一样,且返回值也完全一样的(可以自动转化的类型也不可以)方法,让子类覆盖掉(override)父类的方法。

2.覆盖的时候,不可以让其可见性更低,但是可以用更高的修饰符。

因为父类引用指向子类对象时,调用其重写的方法,如果此时为private,不符合只有自己调用的原则。

12.super

1.属于子类和父类交流的桥梁,通过super可以调用父类中的public方法,但并不是父类的引用,(不是一个引用),和this自引用不一样,不可以返回。

2.使用super调用父类的构造方法,必须是子类构造方法第一个语句;

可以使用表达式;

不可以使用super访问父类的属性和方法,不可以使用子类的成员变量和方法,可以使用静态变量和方法。

3.如果父类没有无参的构造方法,那么子类需要在构造方法第一行,通过super调用一个父类的有参数的构造方法。

13.父类子类引用

1.父类引用可以指向子类对象,但是决定可以调用哪些方法的是引用的类型。

即父类引用只能调用父类中有的方法,子类特有的方法无法调用,即便实际指向的是子类对象。

能调用哪些方法是引用类型决定,调用哪个方法是引用所指向的对象决定

换言之,如果子类没有覆盖某个方法,那么就回去父类中找,如果还没有就回去父类的父类去找。既然引用指向成立,那么必定是有一个父类兜底的。

2.如果确定一个父类引用指向的是子类对象,那么可以强制类型赋值给子类引用。

但是如果指向不符合要求,那么强制类型转化失败。

14.instanceof

一个操作符,用于判断一个引用指向的对象是否是一个类型或者其子类,是则返回true,不是返回false;null一定返回false。

多用于强制类型转换之前判断是否可以转换。

Animal anm=new Cat();
if(anm instanceof(Cat)){
    Cat c=(Cat) anm;
}

15.final

1.修饰类:不可继承

2.修饰方法:不可给覆盖

3.修饰成员变量:(一定要赋值,且赋值一次)只允许在生命时初始化或者构造方法中赋值,其他地方不允许赋值。

如果是静态变量:也一样,必须赋值一次,可以声明时赋值,也可以在静态代码块赋值。

4.不可以修改构造方法

5.修饰局部变量,也是一样,一定要赋值,且赋值一次。

6.修饰引用,则引用指向的对象不可修改,但是对象的内容可以修改

16.继承里的静态方法

1.静态方法是可以被继承的;要求和普通的覆盖相同。

2.用引用调用静态方法,没有覆盖

对比:

非静态方法:能调用的方法取决于引用类型,具体调用哪个取决于指向的对象;

静态方法:能调用的,和具体调用的都是由引用类型决定的。

所以一般不用引用调用静态方法,都是使用类名调用。

追其根源是静态方法直接和类相关,没有this自引用。

17.hashCode和equals方法

1、hashCode相对标识对象之间不一样的int整数;

equals是判断两个对象在逻辑上是否相等;

都是Object类中有的方法,自己写的类要使用这两个方法的时候,一般都是要覆盖的

2、缺省情况下,equals仅仅是比较两个对象的引用是否相等;

覆盖的原则是:如果equals是true,是hashCode相等的充分非必要条件。

3、编译器可以自动生成这个两个方法的覆盖:

equals会逐个比较成员变量是否相等。

hashCode会将成员变量综合起来,使用Object.hash()方法生成哈希码。

18.String判断相等的特殊情况

每一个字符串都是一个对象,且String对象是不可修改的,所以判断字符串是否相等,要使用euqals(),但是如下代码,输出都是true。

String str1="aabb";
String str2="aa"+"bb";

System.out.println(str1==str2);
System.out.println(str1.equals(str2));

java对字符串优化,将字符串统一管理,如果创建的字符串不是很多,新创建一个字符串的时候,会去找是否有值一样的,因为String不可修改,所以就直接返回该引用。

如果字符串很长很长,突破java优化的限制, 那么就会创建两个对象。

总的来说,平常还是要使用equals()比较。

19.动态参数

必须是参数列表中的最后一个参数,类型后加…

fun(String… args){};

调用的时候,可以不传递参数,fun()等效于fun(new String[0])

也可以传递多个参数,fun(“aa”, “bb”,", “cc”)等效于fun(new String[]{“aa” ,“b”,",“cc”})

20.Class类

每个class类的实例,都代表一个类; 通过这个类的Class实例,可以获取一个类所有的信息,包括成员变量、方法等。

class类的实例可以通过object类中的getClass()方法得到,

拥有getName(), getSimpleName()两个基本方法,SimpleName返回省略了包名目录:

getField(String Name)方法,可以获得Field对象, 是对类中成员变量的描述,Field对象拥有多个函数,getName()、 getType()等等方法。getMethod()方法,可以获得Method对象, 是对方法的描述,可以获得参数、返回值。

例如: getMethod(“euqals” object.class),第一 个参数是方法名,第二个参数是动态参数,为方法参数的类型,可以是多个。

21.反射(一)

对属性进行获取的样例:

Cat cat=new Cat("dudu");
Class clazz=Cat.class;
Field nameField=clazz.getField("name");
//通过nameField可以查看某个对象该变量的值。这里查看cat对象的name属性。
System.out.println(nameField.get(cat));
//也可以set
nameField.set(cat,"haha");
//其实等效cat.name
//可以遍历所有变量
for(Field field:clazz.getFields()){
    System.out.println(field.getType()+" "+field.getName());
}

dudu

class java.lang.String name

特别的,如果传递的是静态变量,那么对象传递是空就行

Field field=clazz.getField(“STATIC_MEMBER”);

System.out.println(nameField.get(null));

对方法获取的样例

Cat cat=new Cat("dudu");
Class clazz=Cat.class;
Method sayMethod=clazz.getMethod("say");
sayMethod.invoke(cat);

//调用有参数的静态方法getNameOf(Cat cat);
//第二个参数是变量类型。
Method staticMethod=clazz.getMethod("getNameOf",Cat.class);
String name=(String)staticMethod.invoke(null,cat);
System.out.println(name);

dudu:喵喵

dudu

invoke()第一个参数是对象,第二个参数是变量。返回值未知,需要强制类型转换。

22.反射(二)

对于类中private修饰的变量和方法,可以通过反射取到。

getDeclaredField()

getDeclaredMethod()

//name属性被private修饰
Field nameField=clazz.getDeclaredField("name");
nameField.setAccessible(true);
System.out.println(nameField.get(cat));
//也可以set
nameField.set(cat,"haha");

//say方法被private修饰
Method sayMethod=clazz.getDeclaredMethod("say");
sayMethod.setAccessible(true);
sayMethod.invoke(cat);

23.枚举

public enum TaskStatus{
	//必须在开始的时候,以下列形式,创建所有的枚举对象
    TODO(1),//中间是逗号
    DONE(2);//最后一个是分号
    //可以有属性
    private int id;
    //构造方法必须是private的,不写也是private;
    private TaskStatus(int id){
        this.id=id;
    }
    
    public int getId(){
        return id;
    }
}

枚举和类相比,特殊的地方,在于最开始的地方,调用枚举的构造方法,以创建所有的枚举对象。

构造方法是私有的,所以,该枚举类的实例是一开始创建好的,不许与私自在其他地方创建。

枚举类继承与enum,不允许再继承其他类。

enum类中有一些方法:

  1. 枚举类.values() 获得所有枚举的实例数组

  2. ordinal() 返回某个实例在枚举类中定义的顺序(从0开始)

  3. name() 返回某个实例在枚举类中定义的名字。(大小写敏感)

  4. 枚举类.valueOf(“TODO”) 根据输入获得枚举对象

获取枚举实例的方法

  1. 枚举类.枚举名 TaskStatus.TODO
  2. 枚举类.valueOf(“TODO”) 根据输入获得枚举对象

因为枚举实例只能创建一次,所以两个枚举的引用可以直接使用==进行比较,看是否指向统一引用,判断是否一样。

24.接口相关

  • 接口不能实例化对象,不能被类继承,要被类实现;接口之间可以多继承。

  • 接口中每一个方法也是隐式抽象的,接口中的方法会被隐式的指定为 public abstract

  • 接口中可以含有变量,但是接口中的变量会被隐式的指定为 public static final 变量

  • JDK 1.8 以后,接口里可以有静态方法和方法体了

    重写接口中声明的方法时,需要注意以下规则:

  • 类在实现接口的方法时,不能抛出强制性异常,只能在接口中,或者继承接口的抽象类中抛出该强制性异常。

  • 类在重写方法时要保持一致的方法名,并且应该保持相同或者相兼容的返回值类型。 (当接口继承其他接口时,可以有重复的方法,但是签名一样的方法,则要求返回值必须一样,否则编译错误。)

  • 如果实现接口的类是抽象类,那么就没必要实现该接口的方法。

抽象类:

被abstract 方法修饰,可以有抽象方法,不能被实例化;

有方法的接口:

java8之后,允许有静态方法,私有方法,带有缺省实现的方法

  1. 使用default修饰,可以有方法体;

    此时,如果一个类实现多个接口,且都有同名,同返回值的缺省方法,那么报错

  2. 接口可以有私有方法(private),不需要用default修饰,接口里的私有方法,可以认为是代码直接插入到使用的地方。并且在私有方法中,可以调用接口中其他抽象方法。

public interface Animal{
    //加default修饰
    default void say(){
        System.out.printlm(description()+"default say");
    }
    //抽象方法
    String getName();
    //接口中可以有私有方法,可以通过this 调用抽象方法。
    private String description(){
        return "这是"+this.getName();
    }
}

代码中的this,不是接口本身的this,指向了实现了接口的实例,只能调接口中的方法。

  1. 静态方法:不需要default修饰,可以被实现接口的类继承。缺省是(public static)

特别的,对于实现有缺省方法的接口,面对每个缺省方法,一个类可以有三个选择:

  1. 直接继承使用;

  2. 重新声明此方法为abstract,这部分代码拒之门外,类需要为抽象类

    从这个抽象类之后的继承、实现不可以再读到该缺省方法。

  3. 覆盖,重新实现

25.静态内部类&非公有类

  1. 在类中使用static修饰的类,具有类本身的所有特点,也可以再次套静态内部类(不推荐)。

  2. 也可以使用访问控制符修饰(public、private…),和静态变量一样,也是类的静态组成部分。

  3. 内部类、外部类之间都可以互相直接访问对方的私有属性、方法。

  4. 在外部访问时,需要加上外部类,例如:外部类名.静态内部类;

    在外部的代码,就不再可以直接访问私有属性了。

静态内部类实现单例模式----Math类

​ Math.random();

public static double random(){
    return RandomNumberGeneratorHolder.randomNumberGenerator.netDouble();
}

RandomNumberGeneratorHolder是一个Math类的静态内部类;

private static final class RandomNumberGeneratorHolder{
    static final Random randomNumberGenerator = new Random();
}

内部类中只有一个初始化一次的静态变量;

这样一来,利用了java的类加载机制,静态内部类不会过早初始化,实现单例模式,只有在调用Random之后,才会初始化,且保证只会初始化一次。

非公有类:

  1. 在同一文件内,但是定义在类外。

    主要区别就是不能访问类的private属性;

26.成员内部类

  1. 不可以包含任何静态成分:静态方法、静态变量、静态内部类;

  2. 可以有final static的基本数据类型的变量

  3. 成员内部类中有一个外部类的引用,访问外部的成员变零可以使用该引用。所以也可以访问外部的private属性。

    静态内部类: Phone phone; phone.speed;

    成员内部类:Phone.this.speed;

  4. 如果在外部想创建内部类的对象,写法比较特殊:

    Phone phone = new Phone("一些初始化");
    Phone.CPU cpu = phone.new CPU("default");
    

    需要指明内部类的外部类的引用,这里后面的phone就是指定的外部类的引用。

27.局部内部类

  1. 方法内部的类,叫作局部内部类

  2. 不可以包含静态的成分

  3. 不可以有访问控制符,和成员变量一样,都是类的组成部分。

  4. 可以有static final修饰的基本数据类型变量

  5. 也有一个外部类的引用,故而,也可以访问外部类的private属性,

    类名.this.属性/方法

  6. 除此之外,局部内部类,还可以访问方法的参数和局部变量,但是必须是实际final(声明之后,不可再赋值)。

28.匿名类

匿名类是用来创建接口或者抽象类的实例的;可以出现在任何有代码的地方(赋值、参数传值)。

格式:

实例名 = new 接口名/抽象类名(){
	//类体。必须包含的对抽象方法的实现;
	//此外可以有成员变量。
	//特性和局部内部类类似,访问方法的参数和局部变量,需要使实际final,也可访问外部类私有属性。
}

实现的是抽象类时,如果构造函数有参数,可以再实现匿名内部类的时候正常传参。

如果实例赋值对象时static,那么对标静态内部类的特性。

(外部类.this.私有属性×)

29.异常

所有异常的父类:Throwable

异常的种类(Throwable的两个子类):Error:无法处理的 和Exception :可以处理的

exception分为 checked exception 和unchecked exception。前者必须使用try catch或者throws处理;

Error和RuntimeException是unchecked exception的父类,一般使用 RuntimeException。

不是继承上述两个类的异常,是checked exception。

异常比较重要的信息:类型、错误信息、出错时的调用栈;

自定义异常:封装一些父类的构造方法,也可以自定义一些属性方法;

catch一个没有抛出的checked exception,会报错,java明确认为这个类型的异常不会发生;

catch一个没有抛出的unchecked exception,不会报错;

throws一个没有抛出的checked或者 unchecked exception 都不会报错。

对异常捕获传递,本身是一个很耗资源的操作,调用栈、类型匹配等,所以对于异常处理不可以处理正常的业务。

尽量不要使用throw catch来进行业务操作的返回,类似返回值功能,catch到什么异常就作什么类型的业务操作。

try-catch-finally:

finally认为是在方法返回后,后面的方法前,会在return语句后执行的。无论在return结束还是异常结束,finally都会执行;

在finally内改变return的变量值,是无效的,因为程序认为;

finally内最好不要有return 会把前面的return全部都失效,且会打乱exception的传递。

自动回收资源的try语句

(简化资源相关的异常处理)

资源需要实现AutoCloseable接口

try( MyAutoCloseableResource res1 = new MyAutoCloseableResource("res1");
     MyAutoCloseableResource res2 = new MyAutoCloseableResource("res2")
   ){
    //do
}catch(Exception e){
    //
}

常见的异常:

NPE(NullPointerException):空指针异常

IndexOutOfBoundsException : 索引相关的异常

ClassCastException : 一个类型的引用强转成另一个类型的引用,出现不匹配的属性时

ClassNotFoundException:找不到类 (checked)

IOException:IO相关的 (checked)

30. 泛型

约束控制的元素类型

在方法中定义泛型:Generic Methods

在类型中定义泛型:Generic Type

public class MyGenericClass<First,Second>{
    private First first;
    private Second second;
    ...
        
    public <Another> Another getAnother(Object val){
        return (Another)val;
    }
}

作用:

​ 告诉编译器帮我们检查类型是否匹配,是否一样;

​ 在使用的地方,进行类型转换。

如果在使用泛型时,出现类型转换错误,报错报在调用方。

java里是类型擦除的,并没有记住类型是什么,只是在编译的时候进行检查,在用的时候进行类型转换。

再探:

泛型类型不可以调用方法,因为不知道是什么类型,如果需要使用某个类方法,则需要给定类型的范围。

public class MyGenericClass<MyType extends GrandParent>{
    private MyType val;
    ...
        
    public String getAnother(MyType myType){
        return myType.getName();
    }
}

如上,给定范围之后,可以调用GrandParent的getName()方法。

协变和逆变:

是针对引用类型的,可以用在返回值类型,参数类型,等引用类型上。

创建对象的时候,不可以使用协变和逆变。

协变

  1. 泛型类型不管继承关系,只管严格匹配:

    B是A的子类,但是List<B>不是List<A>的子类;

  2. 使用协变完成上述需求,语法:

    void extMethod(List<? extends Parent> extParam){
        for( Parent parent: extParam){
    
        }
    }
    

    这样这个参数可以接受List引用的泛型类型为Parent或者其子类。

  3. 也可以创建协变的引用,但是在创建对象时,不可以使用。

    List<? extends Parent> list=new ArrayList<>();

    但是使用这个带协变范围的引用,无法让具体的类型满足其参数要求,

    因为这样的引用,可以直接指向类似List<Child> 对象,这样一来,使用这个引用可以add(new Parent()); 但是这个对象实际是一个List<Child> ,就会报错。

逆变:

与协变相反,允许的类型为Parent及其父类;

限制同协变,只是针对引用上,不能在创建对象的时候使用。

使用这个带协变范围的引用,无法让具体的类型满足其参数要求,

语法:

​ List<? super Parent> list= null;

list= new List<? super Parent>()    ×

写入时使用逆变;读取时使用协变。

31.Iterator

Iterable接口,主要功能就是返回一个Iterator<>对象,返回这样一个迭代器进行遍历。

实现Iterable接口,就可以支持forEach。

32.注解 annotation

@Override 重写

@Deprecated 过时

自定义注解

// 注解可以被用在哪个/哪些元素上,多个元素时使用{}
@Target(ElementType.METHOD)
// 注解会被留存到哪个阶段
@Retention(RetentionPolicy.RUNTIME)
//以上是每个注解都必须有的,不显示定义的话,会使用缺省值

// 定义一个自己的注解,需要@interface,实际上这个接口会继承Annotation接口
public @interface PrimaryProperty{
    //支持基本数据类型,Class,String,枚举,其他注解 以及前面类型的数组
    //可以指定缺省值
    String defaultValue() default "N/A";
    
    Class targetClass();
    
    int abc();
    
    Override is() default @Override;  
    
}

//使用的时候--实现增加元数据的效果,
//如果是RUNTIME类型,可以通过反射获得这些注解信息,作为相应功能的配置,实现相应的功能。
@PrimaryProperty(targetClass=Test.class,abc=21)

33.lambda

函数式编程,函数不必依附于某个类而存在,可以作为参数和返回值;

lambda表达式必须能够符合接口中定义的抽象方法,参数、返回值、异常都必须匹配;

(参数)->{代码块}

可以取代只有一个抽象方法的接口(不包括default)

使用List的forEach进行举例:

List的forEach方法

default void forEach(Consumer<? super T> action) {
        Objects.requireNonNull(action);
        for (T t : this) {
            action.accept(t);
        }
    }

其中Consumer接口主要有一个accept函数:

@FunctionalInterface
public interface Consumer<T> {

    /**
     * Performs this operation on the given argument.
     *
     * @param t the input argument
     */
    void accept(T t);
}

匿名内部类的实现:

list.forEach(
	new Consumer<String>(){
		@Override
        public void accept(String s){
            //processString是外部类的静态方法;outside是外部类的变量
            processString(s+outside);    
        }
	}
);

lambda实现:

list.forEach(s->processString(s+outside));
//不使用外部变量,传递静态方法,可以使用:
list.forEach(类名::方法名);
//不使用外部变量,传递非静态方法,可以使用:
list.forEach(实例::方法名);
//不使用外部变量,如果知道参数类型,那么可以传递参数类型里的方法
list.forEach(String::toUpperCase);

流的使用:

list.stream().filter(s-> s.length() > 4).map(String::toUpperCase).forEach(System.out.println);

使用collector让数据重新生成一个list:

List<String> list2 = list.stream().filter(s-> s.length() > 4).map(String::toUpperCase).collect(Collector.tolist());

34.基本数据类型的自动装箱和拆箱

auto boxing, auto unboxing

//自动拆箱
Integer a = 123;
int b = a;
//自动封箱--put,get都会把1封装成实例
Map<Integer, String> map = new HashMap<>();
map.put(1,"壹");
map.get(1);

//对于允许为null的数据结构
map.put(null,"无");
map.get(null);		//是被允许的
for(int key : ,map.keySet()){} 		// 自动拆箱出错

使用三目运算符时,如果出现类型不一致,java会使用自动拆装箱的机制, 只要一个运算中有不同的类型,涉及到类型转换,那么编译器会往下(基本类型)转型,再进行运算。

int a = 12;
Integer b = null;
Integer c = true ? b : a;

正常运算下来,c=b=null,但是会出现NPE;

因为类型不一致,b出现了自动拆箱,null调用intValue(),出现NPE。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值