java进阶版

本文详细介绍了Java中的集合框架,包括List、Set的常见实现类如ArrayList、HashSet、TreeSet及其特性。重点讲解了Lambda表达式的使用,以及如何简化接口实现。同时,探讨了多线程的实现方式,包括Thread类和Runnable接口,并对比了它们的优缺点。此外,还提到了Map集合的种类和常用操作,以及不可变集合的概念。最后,简要提及了反射和流(Stream)的基本用法。
摘要由CSDN通过智能技术生成

Lambda表达式

jdk8之后的新语法形式

/*
(匿名内部类重写方法的形参) ->{
	被重写方法的方法体代码
}
*/

简化接口中只有一个抽象方法的函数式接口

List集合

Set集合

Collection
  • Set:无序、不重复、无索引
  • HashSet:无序、不重复、无索引
  • LinkedHashSet:有序、不重复、无索引
  • TreeSet:可排序(天然排序)、不重复、无索引

HashSet底层原理

(数组+链表、红黑树)JDK8

当链表长度大于8的时候转成红黑树

长度为16 数组名为table 当元素=16*0.75=12时,自动扩容,每次扩容为原来的2倍

哈希值:根据地址根据某种特殊的规则推算出的int类型的数值

哈希表:对增删改查性能都很好的结构

hashset集合hashCode() equals()可以重写 javabean中右键重写

只要结果一样

linkedhashset集合 双链表

TreeSet集合默认的规则

对于数值类型:int double,官方默认按照大小进行升序排序

对于字符型:按照首字母的编号排序

对于对象类型:TreeSet需要自定义规则 implements Comparable<对象类型>

两种方式的比较规则:

如果认为第一个元素大于第二个元素返回正整数即可。

如果认为第一个元素小于第二个元素返回负整数即可。

如果认为第一个元素等于第二个元素返回0即可。

此时TreeSet集合会保留一个元素,认为两者重复。

方式一:在实体类中重写比较规则

public int comparaTo(Apple o){
    return this.weight - o.weight;//会去掉相等的
    return this.weight - o.weight >= 0 ? 1: -1;//相等的也会保留
}

方式二:

注意:如果TreeSet集合存储对象有实现的比较规则,集合也有自带的比较器,默认使用集合自带的比较器排序

如果方式一与方式二冲突,会采用就近原则(采用方式二)

  • 如果元素可以重复,又有索引,索引查询要快 ArrayList基于数组
  • 如果希望元素可以重复,又有索引,增删收尾操作块 LinkedList基于链表
  • 如果希望增删改查都快,但是元素不重复,无序,无索引 HashSet基于哈希表
  • 如果希望增删改查都快,但是元素不重复,有序,无索引 LinkedList基于哈希表和双链表
  • 如果要对对象进行排序 TreeSet 基于红黑树,后续可以用List集合实现排序

可变参数

可以接受多个数据

对外灵活,对内数组

public class Demo {
    public static void main(String[] args) {
        sum();
        sum(10);
        sum(10,20,30);
        sum(new int[]{10,20,30,40});
    }
    //可变参数必须放在形参列表之后
    public static void sum(int...nums){
        //可变参数在方法内部就是一个数组 nums
        System.out.println(Arrays.toString(nums));
    }
}

Collections集合工具类

1、addAll:

public static void main(String[] args) {
        List<String> sets = new ArrayList<>();
    	//简化多行代码 sets.add("xx");
        Collections.addAll(sets,"楚留香","张无忌","陆小凤");
    	System.out.println(sets);
    }

2、shuffle://打乱list集合顺序

public class SetDemo {
    public static void main(String[] args) {
        List<Integer> list = new ArrayList<>();
        Collections.addAll(list,10,20,15,5);
        Collections.shuffle(list);
        System.out.println(list);
    }
}

3、sort:

public class SetDemo {
    public static void main(String[] args) {
        List<Integer> list = new ArrayList<>();
        Collections.addAll(list,10,20,15,5);
        Collections.sort(list);
        System.out.println(list);
    }
}

如果存的是对象需要定义排序规则 implements Comparable<对象类型>

重写比较规则

public int comparaTo(Apple o){
    return this.weight - o.weight;//相等也会保留   属性类型必须是int类型
}

Map集合

Map集合概述

  • Map集合是一种双列集合,每个元素包含两个数据。
  • Map集合的每个元素的格式:Key(键)=value(值)(键值对元素)
  • Map集合也被称为“键值对集合”

整体格式

Collection集合的格式:[元素1,元素2,元素3…]

Map集合的完整格式:{key1=value1 , key2=value2 , key3=value3, …} //这是三个元素

map

Map集合体系的特点

  • Map集合的特点都是键决定的。

  • Map集合的键是无序,不重复,无索引,值不做要求

  • Map集合后面的键对应的值会覆盖前面重复的值

  • Map集合的键值对都可以为null

  • HashMap:无序,不重复,无索引

  • LinkedHashMap:有序,不重复,无索引

  • TreeMap:有序,不重复,无索引

public class SetDemo {
    public static void main(String[] args) {
        Map<String,Integer> maps1 = new HashMap<>();
        Map<String,Integer> maps2 = new LinkedHashMap<>();
        Map<String,Integer> maps3 = new TreeMap<>();         
    }
}

Map常用的API

eg: Map<String,Integer> maps= new HashMap<>();

  • maps.clear();//清空集合
  • maps.isEmpty();//判断是否为空
  • Integer key= maps.get(“value”);//根据键值对的值求对应的key
  • maps.remove(“key”);//根据key来删除当前的键值对 返回的类型应该是当前key对应的value
  • maps.containsKey(“key”);//判断是否包含某个键
  • maps.containsValue(“Value”);//判断是否包含某个值
  • Set keys = maps.keySet(); //将maps中的键放到set集合中
  • Collection values = maps.values();//将maps中的值放到Collection集合中
  • maps.size();//集合的大小,即拥有几个元素
  • map1.putAll(map2);//将集合中map2中元素拷贝到map1中

遍历map集合

方式一:键找值(推荐)

Set<String> keys = maps.keySet();

for(String key : keys){
	int value = maps.get(key);
		System.out.println(key+""+value);
}

方式二:键值对(麻烦)

Set<Map.Entry<String,Integer>> entries = maps.entrySet();
for(<Map.Entry<String,Integer> : entry : entries){
    String key = entry.getKey();
    int value = entry.getValue();
}

方式三:Lambda(特别推荐)

maps.forEach((k,v) ->{
    System.out.println(k + "---->" + v);
});

不可变集合

定义:集合在整个生命周期不可改变,否则报错

//不可变的list集合
public class CollectionDemo {
public static woid main(string[] args) {
List<Double> lists = List.of(569.5,700.5,523.0,570.5);
lists.add(689.0);
system.out.println(lists);
	}
}

//不可变的set集合
Set<String> names = Set.of("迪丽热巴""迪丽热九""马尔扎哈","卡尔眨巴”);
system.out.println(names) ;
                           
//不可变的Map集合
                           

of方法

Stream流

names.stream().filter(s -> s.starsWith("张")).filter 

获取Stream流

1.1、Collection集合

Collection list = new ArrayList<>();

Stream s = list.stream();

1.2、Map集合

Map<String , Integer> maps = new HashMap<>();

Stream keyStream = maps.keySet().stream();

Stream valueStream = maps.values().stream();

Stream<Map.Entry<String,Integer>> keyAndValueStream = maps.entrySet().stream();

1.3、数组

String[] names = {“ab”,“cd”,“ef”,“ghi”};

Stream nameStream = Arrays.stream(names);

// Stream nameStream = Stream.of(name);

常用的API

多线程

方式一:继承Thread类

  1. 定义一个子类MyThread继承Thread,重写run()方法
  2. 创建MyThread类的对象
  3. 调用线程对象的start()方法启动线程(启动后执行的还是run方法)
public class ThreadDemo {
    public static void main(String[] args) {
        Thread thread = new MyThread();
        thread.start();//放在前边才是多线程

        for (int i =  0; i < 5; i++) {
            System.out.println("主线程~~" + i);
        }
    }
}

class MyThread extends Thread{
    @Override
    public void run() {
        for (int i = 0; i < 5; i++) {
            System.out.println("子线程~~"+ i);
        }
    }
}
  • 优点:代码简单

  • 缺点:线程类已经继承Thread,无法继承其他类,不利于扩展

方式二:实现Runnable接口

方案1:定义一个线程任务类MyRunnable实现Runnable接口

  1. 定义一个线程任务类MyRunnable实现Runnable接口,重写run()方法
  2. 创建MyRunnable任务对象
  3. 把MyRunnable任务对象交给Thread处理
  4. 调用线程对象的start()方法启动线程
public class ThreadDemo {
    public static void main(String[] args) {
        Runnable target = new MyRunnable();
        Thread thread = new Thread(target);
        thread.start();

        for (int i = 0; i < 10 ; i++) {
            System.out.println("主线程~" + i);
        }
    }
}

class MyRunnable implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i < 5; i++) {
            System.out.println("子线程~" + i);
        }
    }
}

  • 优点:线程任务类只是实现接口,可以继续继承类和实现接口,扩展性强。

  • 缺点:编程多一层对象包装,如果线程有执行结果是不可以直接返回的。

方案2:匿名内部类

public class ThreadDemo {
    public static void main(String[] args) {

        Runnable target = new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 5; i++) {
                    System.out.println("子线程" + i);
                }
            }
        };
        Thread t = new Thread(target);
        t.start();

        for (int i = 0; i < 5; i++) {
            System.out.println("主线程" + i);
        }
        
        
//		  简化后的写法 
//        new Thread(new Runnable() {
//            @Override
//            public void run() {
//                for (int i = 0; i < 5; i++) {
//                    System.out.println("子线程" + i);
//                }
//            }
//        }).start();
        
        
//		  Lambda写法
//        new Thread(() -> {
//                for (int i = 0; i < 5; i++) {
//                    System.out.println("子线程" + i);
//                }
//        }).start();

均不能返回结果,不适合返回线程结果的业务场景

方式三:JDK5.0新增Callable接口

1、得到任务对象

​ 定义一个实现Callable接口,重写call方法,封装要做的事情。

​ 用FutureTask把Callable对象封装成线程任务对象。

2、把线程对象交给Thread处理

3、调用Thread的start方法启动线程,执行任务

4、线程执行完毕后,通过FutureTask的get方法去获取任务执行的结果

/**
 *  实现Callable接口,用FutureTask把Callable对象封装成线程任务对象
 */
public class ThreadDemo {
    public static void main(String[] args) {
        MyCallable call1 = new MyCallable(100);
        FutureTask<String> f1 = new FutureTask<>(call1);
        Thread t1 = new Thread(f1);
        t1.start();

        MyCallable call2 = new MyCallable(100);
        FutureTask<String> f2 = new FutureTask<>(call2);
        Thread t2 = new Thread(f2);
        t2.start();


        try {
            String rs1 = f1.get();
            System.out.println("第一个:"+rs1);
        } catch (Exception e) {
            e.printStackTrace();
        }


        try {
            String rs2 = f2.get();
            System.out.println("第二个:"+rs2);
        } catch (Exception e) {
            e.printStackTrace();
        }

    }
}

class MyCallable implements Callable<String>{
    //<>应该声明线程执行完毕后返回结果的类型
    private int n;

    public MyCallable(int n) {
        this.n = n;
    }

    @Override
    public String call() throws Exception {
        int sum = 0;
        for (int i = 0; i < 5; i++) {
            sum+=i;
        }

        return "sum=" + sum;
    }
}

优点:线程任务类只是实现结果,可以继续实现接口,扩展性强

缺点:编程复杂

多线程3

反射

获取class类对象

  • 方式一:Class c1 = Class.forName(“全限名”);
  • 方式二:Class c2 = 类名.class
  • 方式三:Class c3 = 对象.getClass();

获取构造器对象

getDeclareConstructors()

getDeclareConstructors(Class<?> 参数)

public newInstance(Object … intitargs)

如果构造器是private类型的,暴力反射

setAccessible(boolean)

反射破坏了封装性,私有的也可以执行

定位全部成员变量

Field[ ] fields = c.getDeclaredFields();

根据名称定位某一个成员变量

Field f = c.getDeclaredField(“name”);

赋值

ageF.setAcessiable(ture);

Student s = new Student();

ageF.set(s , 18);//s.setAge(18);

取值

int age = (int) ageF.get(s);

Class c = Dog.class;

Methods[ ] methods = c.getDeclaredMethods();

//Method method = c.getDeclaredMethod(“name”,Object.class);

method.getName();//方法名称

method.getReturnType();//返回值类型

method.getParameterCount();//参数个数

方法.invoke(对象 , 参数);//返回方法的返回值

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

山鸟同学

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值