Java泛型、枚举和静态导入

泛型

JDK1.5加入的新特性,泛型的本质是参数化类型,即操作的数据类型被指定为一个参数。安全简单,且所有的强制类型转换都是隐式和自动进行的,提高代码的重用率。

定义
概念:

将对象类型作为参数,指定到其它类或者方法上,从而保证类型转换的安全性和稳定性。

语法:

类型<E> 对象 = new 类型<E>();

  • 解析:
    • <> 是泛型的特征
    • E 表示某种数据类型,也可用其它字母,实际使用中需要用明确类型换掉 E
深入了解
泛型接口,类,方法
  • 泛型接口:

    • 泛型接口与泛型类的定义及使用基本相同。泛型接口常被用在各种类的生产器中。

    • 只能用在抽象方法上

    • public interface Generator<T> {
          public T next();
      }
      
      /**
       * 未传入泛型实参时,与泛型类的定义相同,在声明类的时候,需将泛型的声明也一起加到类中
       * 即:class FruitGenerator<T> implements Generator<T>{
       * 如果不声明泛型,如:class FruitGenerator implements Generator<T>,编译器会报错:"Unknown class"
       */
      class FruitGenerator<T> implements Generator<T>{
          @Override
          public T next() {
              return null;
          }
      }
      
  • 泛型类:

    • 用于类的定义中,被称为泛型类

    • 最典型的就是各种容器类,如:List、Set、Map

    • 只能用在成员变量上,只能使用引用类型

    • class 类名称 <E[,T]>{
        .....
      }
      
    • 泛型类,是在实例化类的时候指明泛型的具体类型;泛型方法,是在调用方法的时候指明泛型的具体类型 。

  • 泛型方法

    • 是在调用方法的时候指明泛型的具体类型 。

    • 返回值前面加上

    • /**
       * 泛型方法的基本介绍
       * @param tClass 传入的泛型实参
       * @return T 返回值为T类型
       * 说明:
       *     1)public 与 返回值中间<T>非常重要,可以理解为声明此方法为泛型方法。
       *     2)只有声明了<T>的方法才是泛型方法,泛型类中的使用了泛型的成员方法并不是泛型方法。
       *     3)<T>表明该方法将使用泛型类型T,此时才可以在方法中使用泛型类型T。
       *     4)与泛型类的定义一样,此处T可以随便写为任意标识,常见的如T、E、K、V等形式的参数常用于表示泛型。
       */
      public <T> T genericMethod(Class<T> tClass)throws InstantiationException ,
        IllegalAccessException{
              T instance = tClass.newInstance();
              return instance;
      }
      
泛型方法和可变参数
  • public <T> void printMsg( T... args){
        for(T t : args){
            Log.d("泛型测试","t is " + t);
        }
    }
    
泛型的继承
  • package com.bigdata.practice1011;
    
    public abstract class FanXin <T1, T2>{
        T1 name;
        public abstract void setName(T2 sex);
    }
    
  • 保留父类泛型

    • // 全保留
      package com.bigdata.practice1011;
          // 泛型父类 子类全部保留父类的泛型
      public class FanXin1<T1,T2> extends FanXin<T1,T2>{
          @Override
          public void setName(T2 sex) {
              
          }
      }
      
      // 保留一个
      package com.bigdata.practice1011;
          // 继续全写泛型不合适 得把用的那个泛型写成具体类型
      public class FanXin2<T1> extends FanXin<T1, String> {
          @Override
          public void setName(String sex) {
              
          }
      }
      
  • 不保留父类泛型

    • package com.bigdata.practice1011;
          // 不保留父类的泛型
              // 父类的泛型显示
              // 泛型擦除:实现或继承父类的子类没有指定类型 类似于Object【不等于Object,<Object>编译不通过】
      
      public class FanXin3 extends FanXin{
          @Override
          public void setName(Object sex) {
      
          }
      }
      class FanXin4 extends FanXin<String, Integer>{
          @Override
          public void setName(Integer sex) {
      
          }
      }
      
  • 子类重写父类的方法,泛型类型随父类而定 子类使用父类的属性,该属性类型随父类定义的泛型

通配符
  • T、K、V、E 等泛型字母为有类型,类型参数赋予具体的值
  • 未知类型 类型参数赋予不确定值,任意类型
  • 只能用在声明类型、方法参数上,不能用在定义泛型类上
泛型上下界:
上界 <= 【extends】
  • 语法:? extends List
  • 范围:指定的类必须是继承某个类,或者实现了某个接口(不是implements),即<=
  • 注意:一般用于限制操作 不能使用在添加数据上,一般都是用于数据的读取
下界 >= 【super】
  • 语法:? super List
  • 范围: 即父类或本身
  • 注意:一般用于下限操作
大概阅读源码理解一下就好了!
泛型嵌套

HashMap使用了泛型的嵌套

	Map<String, String> map =  new HashMap<String,String>();
    map.put("a", "张三");
    map.put("b", "李四");
    Set<Entry<String, String>> set = map.entrySet();
    for (Entry<String, String> entry : set) {
     System.out.println(entry.getKey()+":"+entry.getValue());
    }
注意:
static和泛型:

静态方法有一种情况需要注意一下,那就是在类中的静态方法使用泛型:静态方法无法访问类上定义的泛型;如果静态方法操作的引用数据类型不确定的时候,必须要将泛型定义在方法上。即使该类已经定义为泛型类。

// 泛型参数T2其实没用 静态方法的泛型T2和类定义的泛型T2没有任何关系
public class FanXin <T1, T2>{
    T1 name;

    public static <T2> T2 get(T2 name){
        T2 t2 = name;
        return t2;
    };
}
泛型和数组

不能创建一个确切的泛型类型的数组,使用通配符创建泛型数组是可以的

List<String>[] ls = new ArrayList<String>[10]; // 不行
List<?>[] ls = new ArrayList<?>[10];  // 可以
List<String>[] ls = new ArrayList[10];  // 可以
泛型没有多态,泛型没有数组
枚举类
定义理解
概念:

JDK1.5引入的一种新类型枚举(Enum),是指一组固定常量组成的类型。其实是一种类型,是java.lang.Enum的子类。

如果学过单例模式,我们可以理解为枚举就是多例模式,一个类有多个实例,但实例个数不是越多越好的,是有限的。

语法:
修饰符 enum 枚举名{
	枚举常量值1;
	枚举常量值2;
}
// 调用
枚举名.枚举常量值1;
注意:
  • enum 是关键字,小写的 ;
  • 枚举型其实就是本类的实例;
  • 多个枚举项之间使用逗号分隔,最后一个枚举项需要给出分号!如果只有枚举项(没有构造器,方法,实例变量)则可以省略分号。
  • 不可使用new来创建枚举类对象,枚举类的枚举项就是实例,所以在外面用类面点来调用
使用

通常用枚举表示一组常用且个数有限的值,用于实现对输入值进行约束检查

内部类的形式去给到性别属性的控制:

package com.bigdata.practice1008;

/**
 * 泛型 将对象类型作为参数 指定到其它类或者方法上
 * 多个泛型参数用逗号隔开  整体用一对尖括号括起来
 * @param <T>
 * 1.泛型类
 * 2.泛型属性
 * 3.泛型方法
 * 4.泛型参数
 * 5.泛型返回值
 *
 */
public class Person<T> {

    private String name;
    private int age;
    private sexType sex;
    private T personType;

    public Person() {

    }

    enum sexType{,}

    public Person(String name, int age, sexType sex, T personType) {
        this.name = name;
        this.age = age;
        this.sex = sex;
        this.personType = personType;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public sexType getSex() {
        return sex;
    }

    public void setSex(sexType sex) {
        this.sex = sex;
    }

    public T getPersonType() {
        return personType;
    }

    public void setPersonType(T personType) {
        this.personType = personType;
    }

    public static <T> void printInfo(T st){
        System.out.println("泛型类中的静态方法!");
        if (st instanceof Student){
            System.out.println("OK!");
        }
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", sex=" + sex +
                ", personType=" + personType +
                '}';
    }
}
枚举和switch
说明
  • switch中不可使用枚举类名称
  • 编译器会根据switch(s)中的s来确定每个枚举类型
  • case中直接使用枚举项
示例
public enum Signal{
	RED, GREEN, BLANK, YELLOW; 
}

public class TrafficLight {  
    Signal color = Signal.RED;  
    public void change() {  
        switch (color) {  
        case RED:  
            color = Signal.GREEN;  
            break;  
        case YELLOW:  
            color = Signal.RED;  
            break;  
        case GREEN:  
            color = Signal.YELLOW;  
            break;  
        }  
    }  
}
java.lang.Enum

Java 中的每一个枚举都继承自 java.lang.Enum 类。当定义一个枚举类型时,每一个枚举类型成员都可以看作是 Enum 类的实例,这些枚举成员默认都被 final、public, static 修饰,当使用枚举类型成员时,直接使用枚举名称调用成员即可

方法名称描述
values()以数组形式返回枚举类型的所有成员
valueOf()将普通字符串转换为枚举实例
compareTo()比较两个枚举成员在定义时的顺序
ordinal()获取枚举成员的索引位置
枚举类
  • 可以拥有自己的方法
  • 可以拥有自己的构造
EnumMap 与 EnumSet

为了更好地支持枚举类型,java.util 中添加了两个新类:EnumMap 和 EnumSet。使用它们可以更高效地操作枚举类型。

EnumMap 类

EnumMap 是专门为枚举类型量身定做的 Map 实现。虽然使用其他的 Map(如 HashMap)实现也能完成枚举类型实例到值的映射,但是使用 EnumMap 会更加高效。

HashMap 只能接收同一枚举类型的实例作为键值,并且由于枚举类型实例的数量相对固定并且有限,所以 EnumMap 使用数组来存放与枚举类型对应的值,使得 EnumMap 的效率非常高。

EnumSet
  • EnumSet 是枚举类型的高性能 Set 实现,它要求放入它的枚举常量必须属于同一枚举类型。EnumSet 提供了许多工厂方法以便于初始化。
  • allOf(Class element type) 创建一个包含指定枚举类型中所有枚举成员的 EnumSet 对象
  • complementOf(EnumSet s) 创建一个与指定 EnumSet 对象 s 相同的枚举类型 EnumSet 对象,并包含所有 s 中未包含的枚举成员
  • copyOf(EnumSet s) 创建一个与指定 EnumSet 对象 s 相同的枚举类型 EnumSet 对象,并与 s 包含相同的枚举成员
  • noneOf(<Class elementType) 创建指定枚举类型的空 EnumSet 对象
  • of(E first,e…rest) 创建包含指定枚举成员的 EnumSet 对象
  • range(E from ,E to) 创建一个 EnumSet 对象,该对象包含了 from 到 to 之间的所有枚举成员
静态导入
理解

在一个类中使用其它类的静态属性和静态方法时,需要静态导入。

使用

直接在前面用 import static 包名;导入,或者类名点去直接调用

不推荐使用,有的时候同包不同类的同名函数或者同名参数不太好处理

lambda表达式
简介
概念:

lambda,其实是数学符号中的 λ,一个希腊字母。拉姆达 Lambda(大写Λ,小写λ),是第十一个希腊字母;在计算机术语中,Lambda 多表达式”是一个匿名函数,可以包含表达式和语句,并且可用于创建委托或表达式目录树类型。Java 8 引入的 Lambda 表达式的主要作用就是简化部分的写法。

理解:
  • Lambda表达式本身就是一个接口的实现
  • 把“一块代码”赋给了一个变量。而“这块代码”,或者说“这个被赋给一个变量的函数”,就是一个Lambda表达式

以Lambda语法创建线程和匿名内部类创建线程的区别:

@FunctionalInterface
public interface Runnable {
    /**
     * When an object implementing interface <code>Runnable</code> is used
     * to create a thread, starting the thread causes the object's
     * <code>run</code> method to be called in that separately executing
     * thread.
     * <p>
     * The general contract of the method <code>run</code> is that it may
     * take any action whatsoever.
     *
     * @see     java.lang.Thread#run()
     */
    public abstract void run();
}
public static void main(String[] args) {
    // 用匿名内部类的方式来创建线程
    new Thread(new Runnable() {
        @Override
        public void run() {
            System.out.println("我是一个线程啊");
        }
    });

    // 使用Lambda来创建线程
    new Thread(() -> System.out.println("我是一个线程啊"));
}
使用
接口的实现
  • 1.new实现类
  • 2.new接口自己匿名类借助
  • 3.lambda表达式【只能去实现一个抽象方法的接口,用 @FunctionalInterface 注解的接口】
语法
  • 语法:(方法参数) -> {方法要实现的内容}

  • 1.语法格式一:无参,无返回值,Lambda 体只需一条语句。

    示例:

    Runnable r1 = () -> System.out.println("Hello Lambda!"); 
    

    2.语法格式二:Lambda 需要一个参数。

    示例:

    Consumer<String> con = (x) -> System.out.println(x);
    

    3.语法格式三:Lambda 只需要一个参数时,参数的小括号可以省略。

    示例:

    Consumer<String> con = x -> System.out.println(x);
    

    4.语法格式四:Lambda 需要两个参数,并且有返回值。

    示例:

    Comparator<Integer> com = (x, y) -> {
       System.out.println("函数式接口");
       return Integer.compare(x, y);
    };
    

    5.语法格式五:当 Lambda 体只有一条语句时,return 与大括号可以省略。

    示例:

    Comparator<Integer> com = (x, y) -> Integer.compare(x, y);
    

    6.Lambda的表达式的参数不用去显示声明类型,jvm ”上下文推断出“类型

  • 使用Labmda表达式需要函数式编程接口,接口上加上 @FunctionalInterface注解(标记着这个接口只有一个抽象方法)

函数式编程接口

接口上加上 @FunctionalInterface注解(标记着这个接口只有一个抽象方法)

内部的函数式编程接口的学习和Stream流一起

lambda表达式的特征
  • 可选的类型声明:不需要声明参数类型,编译器可以自动识别参数类型。
  • 可选的参数圆括号:一个参数无须使用圆括号,但多个参数则需要使用圆括号。
  • 可选的花括号:如果函数体只有一条语句,则不需要使用花括号。
  • 可选的返回关键字:如果函数体只有一条语句,则编译器会自动返回该语句执行的结果;如果有多条语句且有返回值,那么在花括号中需要使用return语句来返回结果。

Lambda结合FunctionalInterface Lib, forEach, stream(),method reference等新特性可以使代码变的更加简洁!后面再来

可变参数:
定义
  • A、 可变参数:适用于参数个数不确定,类型确定的情况,java把可变参数当做数组处理。
  • B、 注意:可变参数必须位于最后一项。
特点
  • A、 只能出现在参数列表的最后;
  • B、 …位于变量类型和变量名之间,前后有无空格都可以;
  • C、 调用可变参数的方法时,编译器为该可变参数隐含创建一个数组,在方法体中以数组的形式访问可变参数。
package com.bigdata.practice1011;

public class ChangeParam {

	public static void main(String[] args) {
		append(25, new String[] {"AA", "Cc"});
		append(34, "AA", "BB");
	}
	
	/**
	 * 可变参数:
	 * 必须写在参数列表最后,
	 * 可以当作数组使用
	 * 传参是可以是显示声明数组传入参数,也可以是单个单个传入
	 * ... 和参数类型与参数变量之间可以有空格可以没有空格
	 */	
	public static void append(int a, String... strs) {
		StringBuilder sb = new StringBuilder();
		for (int i = 0; i < strs.length; i++) {
			System.out.println(strs[i]);
			sb.append(strs[i]);
		}
		System.out.println(sb.toString());
	}
}

调用可变参数的方法时,编译器为该可变参数隐含创建一个数组,在方法体中以数组的形式访问可变参数。

package com.bigdata.practice1011;

public class ChangeParam {

	public static void main(String[] args) {
		append(25, new String[] {"AA", "Cc"});
		append(34, "AA", "BB");
	}
	
	/**
	 * 可变参数:
	 * 必须写在参数列表最后,
	 * 可以当作数组使用
	 * 传参是可以是显示声明数组传入参数,也可以是单个单个传入
	 * ... 和参数类型与参数变量之间可以有空格可以没有空格
	 */	
	public static void append(int a, String... strs) {
		StringBuilder sb = new StringBuilder();
		for (int i = 0; i < strs.length; i++) {
			System.out.println(strs[i]);
			sb.append(strs[i]);
		}
		System.out.println(sb.toString());
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值