JavaWeb (day7)

1.泛型的简介

1.1为什么要使用泛型

一般使用在集合上

比如现在把一个字符串类型的值放入到集合里面,这个时候,这个值放入到集合之后,失去本来类型,只能是 object 类型,这个时候,比如想要对这个值进行类型转换,很容易出现类型转换错误,怎么解决这个问题,可以使用泛型类来解决。

1.2在集合上如何使用泛型

  • 常用的集合 list set map

  • 泛型语法 集合<String> 比如 List<String>

1.3 、在泛型里面写是一个对象 Stirng 不能写基本数据类型

写基本数据类型的包装类

  • byte —— Byte
  • short —— Short
  • int —— Integer
  • long —— Long
  • float —— Float
  • double —— Double
  • char —— Character
  • boolean —— Boolean

2.泛型类的使用

2.1、泛型类在 list 上的使用

代码:

List <String> list=new ArrayList<String>();
list.add("aaa") ;
list.add("bbb") ;
list.add("ccc") ;
//遍历 list

//普通 for 循环
for(int i=0;i<list.size();i++){
String s=list.get(i);
System.out.print(s);
}
//使用增强 for
for(String s1:list){
System.out.print(s1);
}
//使用迭代器遍历
Iterator<String> it=list.iterator();
while(it.hasNext()){
System.out.print(it.next());
}

2.2、泛型使用在 set 集合上

set 集合特点:无序,唯一
代码:

Set <String> set=new  HashSet<String>();
list.add("www") ;
list.add("qqq") ;
list.add("zzz") ;
//遍历 set ,有两种方式
//for(String   s2 : set){
System.out.print(s2);
}
//使用迭代器遍历
Iterator<String> it1=set.iterator();
while(it1.hasNext()){
System.out.print(it1.next());
}

2.3、在 map 上使用泛型

代码:

Map<String,String> map=new HashMap<String,string>();
map.put("aaa","111");
map.put("bbb","222");
map.put("ccc","333");
 //遍历 map 有两种遍历方式
//1.获取所有的 key,通过 key 得到 value 使用 get 方法
//获取所有的 key
Set<String> sets=map.keySet();
//遍历所有 key 返回的 set
for(String key:sets){
String value=map.get(key);
System.out.print(key+“    : ”+value);
}

//2.获取 key 和 value 的关系
Set <Entry<String,String>> sets1 =map.entrySet();
for(Entry<String , String> entry : sets1){
String keyv=entry.getKey();
String valuev=entry.getValue();
System.out.print(keyv+":"+valuev);
} 

2.4 泛型使用在方法上

定义一个数组,实现指定位置上数组元素交换

方法逻辑相同,只是数据类型不同,这个时候使用泛型方法

public static <T> void swap1(T[] arr,int a,int b){
T temp =arr[a];
arr[a]=arr[b];
arr[b] =temp;
}

2.5 泛型在类上的使用

代码:

public class Test<T>{
T   aa;
public void test1(T   bb){}
//写一个静态方法在类上面定义泛型,不能在静态方法里面使用
public static <A> void test2(A  cc1){}
}

3.枚举的简介

3.1、什么是枚举

  • 需要在一定的范围内取值,这个值只能是这个范围内的任意一个
  • 现场取景:交通信号灯,有三种颜色,但是每次只能亮三种颜色里面的任意一个

使用一个关键字 enum

enum Color3{
RED 、 GREEN 、 YELLOW
}

枚举的构造方法也是私有的

3.2 特殊的枚举操作

  • 在枚举里面有构造方法
    ——构造方法有参数,需要在每个实例上都写参数
  • 在枚举里面有抽象方法
    ——在枚举的每个实例里面都重写这个构造方法
enum color{
RED("red") {
public   void  print1(){
System.out.print("red");
}
},GREEN("green")
 {
public   void  print1(){
System.out.print("green");
}
},YELLOW("yellow") {
public   void  print1(){
System.out.print("yellow");
}
}
//构造方法
private color(String  name){
}
//抽象方法  --  在枚举的每个实例里面都重写这个构造方法
public  abstract  void  print1();
}

4.枚举 api 的操作

  • name():返回枚举的名称
  • ordinal():枚举的下标,下标从零开始
  • valueof(class<T> enumType,String name):得到枚举的对象
    还有两个方法,都是这两个方法不在 api 里面,编译的时候生成两个方法
  • valueof(String name)转换枚举对象
  • values()获得所有枚举对象数组

练习:
1.知道枚举对象,得到枚举名称和下标

public void test(){
color     c100=color.RED;
String  name=c100.name;  //得到枚举名称
int idx=c100.ordinal();//得到枚举下标
}
enum color(
RED,GREEN,YELLOW
)

2.知道枚举名称,得到枚举对象和下标

public void test(){
String  name1="GREEN";
color  c1=color.valueOf(name1);//得到枚举对象
int idx=c1.ordinal();//得到枚举下标
}
enum color(
RED,GREEN,YELLOW
)

3.知道枚举下标,得到枚举对象和名称

public void test(){
int   idx2=2;
color[]  cs=color.values();//得到枚举对象数组
color  c2=cs[idx2];  //根据下标得到对象
String  name=c2.name(); //根据对象得到名称
}
enum color(
RED,GREEN,YELLOW
)

5.自动拆装箱

装箱:把基本的数据类型转换成包装类
拆箱:把包装类转换成基本的数据类型

//自动装箱
Integer  i=10;
//自动装箱
int m=1;

在 jdk 1.4里面如何实现装箱和拆箱

public void  test1(){
//装箱
Integer  m = new  Integer(10);
//拆箱
int  a = m.intValue();
}

jdk 向下兼容

——比如: jdk 1.4 里面写的代码,这个时候到 5.0 里面也可以运行

6.增强 for 循环

1.语法:

for( String  s :  list){
   System.out.println(s);
}

2.使用场景:

  • 数组:实现 Iterable 接口的集合 可以使用增强 for 循环

3.在集合上使用增强 for 循环遍历

  • list set 实现 Iterable 接口,所以可以使用增强 for 循环

  • map 不能使用增强 for 循环,没有实现 Interator 接口,所以不能使用

4.增强 for 循环出现的目的:为了替代迭代器
增强 for 底层就是迭代器实现的

7.内容补充

练习:实现一个泛型方法,接受任意类型的数组,颠倒数组中的所有元素

public  static  <T> void  reverse(T[]  arr1){
for(int i=0;i<arr1.length/2;i++){
 T temp =arr1[i];
 arr1[i]=arr1[arr1.length-i-1];
 arr1[arr1.length-i-1]=temp;
}
}

8.可变参数

应用场景:
实现两个数相加,实现三个数相加,四个数相加

如果实现多个方法,这些方法里面逻辑基本相同,唯一不同的是传递的参数个数,这时候可以使用可变参数

1.可变参数定义方法

数据类型...数组名称
可以理解为一个数组,这个数组存储传递过来的参数

public static void add1(int...nums){
int sum=0;
for(int i=0;i<nums.length;i++){
sum+=nums[i];
}
System.out.print(sum);
//输出结果:
//30
//60
//100
}
public static void main(String[] args){
add1(10,20);
add1(10,20,30);
add1(10,20,30,40);
}

注意的地方:
(1)可变参数需要写在方法的参数列表中,不能单独定义
(2)在方法的参数列表中只能有一个可变参数
(3)方法的参数列表中的可变参数,b必须放在参数最后

add1(int  a , int...nums)

9.反射

9.1 反射的原理

1.应用在一些通用性比较高的代码中

2.后面学到的框架,大多数都是使用反射来实现的

3. 在框架开发中,都是基于配置文件开发的
——在配置文件中配置了类,可以通过反射得到类中的 所有内容,可以让类中的某个方法来执行
4.类中的所有内容:属性、没有参数的构造方法、有参数的构造方法、普通方法
5.画图分析反射的原理

1.首先需要 java 文件保存到本地硬盘 .java
2.编译java 文件,成 .class文件
3.使用 jvm ,把 class 文件通过类加载加载到内存中
4.万事万物皆是对象,class 文件在内存中使用 class 类表示
5.当使用反射的时候,首先需要获取到class 类,得到了这个类之后,就可以得到 class 文件里面的所有内容——包含属性,构造方法,普通方法
6.属性通过一个类 Filed
7.构造方法通过一个类 constructor
8.普通方法通过一个类 Method

9.2 使用反射操作类里面的属性

  • 首先获取到 class 类
     Class clazz1=person.class;
     Class clazz2=new person().getClass();
     Class clazz3=Class.forName("day06.person");
  • 操作无参数的构造方法
public void test1() throws InstantiationException, IllegalAccessException, ClassNotFoundException {
        //得到 class
        Class c3=Class.forName("day06.person");
        //得到 person 实例
        person p=(person)c3.newInstance();
        //设置值
        p.setName("zhangsan");
        System.out.println(p.getName());
    }
  • 操作有参数的构造方法
public void test2() throws ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
        Class c1=Class.forName("day06.person");
        //传递有参数的构造方法里面的参数类型,类型使用 class 形式传递
        Constructor  cs=c1.getConstructor(String.class,String.class);
        //通过有参数的构造方法设置值
        person p1=(person) cs.newInstance("lisi","100");
        System.out.println(p1.getId()+" "+p1.getName());
    }
  • 使用属性来操作属性
public void test3() throws ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
        try {
        Class cc=Class.forName("day06.person");
        //得到 person 类的实例
        person p=(person) cc.newInstance();
        //通过这个方法得到属性,参数是属性的名称
        Field f1=cc.getDeclaredField("name");
        //操作的是私有属性,不让操作,需要设置可以操作私有属性setAccessible(true)
        f1.setAccessible(true);
        //设置name的值
        f1.set(p , "wangwu");//相当于 p.name="wangwu"
        }catch(Exception e) {
            e.printStackTrace();
        }
    }
  • 使用泛型操作普通方法
    使用 Method 类表示普通方法
    public void test4() throws ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
        
        Class c4=Class.forName("day06.person");
        //得到 person 实例
        person p4=(person) c4.newInstance();
        //得到普通方法
        //传递两个参数,第一个参数:方法名称第二个参数:通过方法设置的值
        Method  m1=c4.getDeclaredMethod("setname", String.class);
        //让 setName方法执行,执行设置值
        m1.invoke(p4, "niuqi");
       System.out.println(p4.getName());
    }
    

推荐阅读更多精彩内容