java语言基础

集合

集合按照其存储结构可以分为两大类,分别是单列集合java.util.Collection和双列集合java.util.Map

Collection集合

Collection:单列集合类的根接口,有两个重要的子接口,分别是java.util.Listjava.util.Set
List:特点是元素有序、元素可重复,主要实现类有数组结构的java.util.ArrayList和双向链表结构的java.util.LinkedList
Set:特点是元素无序,而且不可重复,主要实现类有采用数组+链表+红黑树实现的java.util.HashSetjava.util.TreeSet。在HashSet下面有一个子类 java.util.LinkedHashSet ,它是链表和哈希表组合的一个数据存储结构,有序。
应用场景
想保证插入元素的唯一性,也就是不想有重复值出现,可以选择Set实现类

HashSet集合存储数据的结构

在这里插入图片描述

Iterator迭代器

1.迭代:在取元素之前先要判断集合中有没有元素,如果有,就把这个元素取出来,继续在判断,如果还有就再取出出来。一直把集合中的所有元素全部取出。这种取出方式专业术语称为迭代

public class IteratorDemo {
  	public static void main(String[] args) {
        // 使用多态方式 创建对象
        Collection<String> coll = new ArrayList<String>();

        // 添加元素到集合
        coll.add("串串星人");
        coll.add("吐槽星人");
        coll.add("汪星人");
        //遍历
        //使用迭代器 遍历   每个集合对象都有自己的迭代器
        Iterator<String> it = coll.iterator();
        //  泛型指的是 迭代出 元素的数据类型
        while(it.hasNext()){ //判断是否有迭代元素
            String s = it.next();//获取迭代出的元素
            System.out.println(s);
        }
  	}
}

泛型

好处

  • 将运行时期的ClassCastException,转移到了编译时期变成了编译失败
  • 避免了类型强转的麻烦

泛型通配符:<?>

tips:泛型不存在继承关系 Collection< Object> list = new ArrayList< String>();这种是错误的

泛型的上限

  • 格式类型名称 <? extends 类 > 对象名称
  • 意义只能接收该类型及其子类

泛型的下限

  • 格式类型名称 <? super 类 > 对象名称
  • 意义只能接收该类型及其父类型

Collections集合工具类

用于对集合进行操作,添加元素,乱序,排序等

Map接口

常用集合
HashMap:存储数据采用的哈希表结构,元素的存取顺序不能保证一致。由于要保证键的唯一、不重复,需要重写键的hashCode()方法、equals()方法。
LinkedHashMap:HashMap下的子类,存储数据采用的哈希表结构+链表结构。通过链 表结构可以保证元素的存取顺序一致;通过哈希表结构可以保证的键的唯一、不重复。

Debug

使用IDEA的断点调试功能,查看程序的运行过程

  1. 在有效代码行,点击行号右边的空白区域,设置断点,程序执行到断点将停止,右键打开debug窗口
    在这里插入图片描述

异常

指的是程序在执行过程中,出现的非正常的情况,终会导致JVM的非正常停止。 在Java等面向对象的编程语言中,异常本身是一个类,产生异常就是创建异常对象并抛出了一个异常对象。Java处理异常的方式是中断处理

图解
在这里插入图片描述

线程与同步

1.每个执行线程都有自己独立的栈
在这里插入图片描述

同步代码块

synchronized关键字可以用于方法中的某个区块中,表示只对这个区块的资源实行互斥访问

同步锁

对象的同步锁只是一个概念,可以想象为在对象上标记了一个锁.

  1. 锁对象 可以是任意类型。
  2. 多个线程对象 要使用同一把锁。

注意:在任何时候,最多允许一个线程拥有同步锁,谁拿到锁就进入代码块,其他的线程只能在外等着 (BLOCKED)。

public class Ticket implements Runnable {
    private int ticket = 100;
    Object lock = new Object();

    @Override
    public void run() {
        //每个窗口卖票的操作          
        // 窗口 永远开启
        synchronized (lock){
            if(ticket>0){//有票,可卖
                try{//出票操作
                    Thread.sleep(50);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

同步方法

同步方法:使用synchronized修饰的方法,保证A线程执行该方法的时候,其他线程只能在方法外等着

Lock锁

public class Ticket implements Runnable {
    private int ticket = 100;
    Lock lock = new ReentrantLock();

    @Override
    public void run() {
        //每个窗口卖票的操作          
        // 窗口 永远开启
        while (true) {
            lock.lock();
            if (ticket > 0) {
                try {
                    Thread.sleep(50);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            lock.unlock();
        }
    }
}
线程状态导致状态发生条件
NEW(新建)线程刚被创建,但是并未启动。还没调用start方法。
Runnable(可 运行)线程可以在java虚拟机中运行的状态,可能正在运行自己代码,也可能没有,这取决于操 作系统处理器。
Blocked(锁阻 塞)当一个线程试图获取一个对象锁,而该对象锁被其他的线程持有,则该线程进入Blocked状 态;当该线程持有锁时,该线程将变成Runnable状态。
Waiting(无限 等待)一个线程在等待另一个线程执行一个(唤醒)动作时,该线程进入Waiting状态。进入这个 状态后是不能自动唤醒的,必须等待另一个线程调用notify或者notifyAll方法才能够唤醒。
Timed Waiting(计时 等待)同waiting状态,有几个方法有超时参数,调用他们将进入Timed Waiting状态。这一状态 将一直保持到超时期满或者接收到唤醒通知。带有超时参数的常用方法有Thread.sleep 、 Object.wait。
Teminated(被 终止)因为run方法正常退出而死亡,或者因为没有捕获的异常终止了run方法而死亡。

调用wait和notify方法需要注意的细节

  1. wait方法与notify方法必须要由同一个锁对象调用
  2. wait方法与notify方法是属于Object类的方法的
  3. wait方法与notify方法必须要在同步代码块或者是同步函数中使用在这里插入图片描述
    ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200606211929460.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MzYzODYxNA==,size_16,color_FFFFFF,t_70


Lock类

package com.aa.test.useThread;

public class Oats {
    String mate;
    boolean flag=false;
}

宝宝线程类

package com.aa.test.useThread;

public class Baby extends Thread {
    private Oats oats;

    public Baby(String name, Oats oats) {
        super(name);
        this.oats = oats;
    }

    @Override
    public void run() {
        while (true) {
            synchronized (oats) {
                if (oats.flag == false) {
                    try {
                        oats.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println(this.getName() + "在吃" + oats.mate + "燕麦");
                oats.flag = false;
                oats.notify();
            }
        }
    }
}

厨师线程类

package com.aa.test.useThread;

public class Chef extends Thread {
    private Oats oats;

    public Chef(String name, Oats oats) {
        super(name);
        this.oats = oats;
    }

    @Override
    public void run() {
        int count=6;
        while (count>0) {
           synchronized (oats){
               if (oats.flag == true) {
                   try {
                       oats.wait();
                   } catch (InterruptedException e) {
                       e.printStackTrace();
                   }
               }
               if(count%2==0){
                   oats.mate="牛奶";
               }
               else {
                   oats.mate="豆乳";
               }
               System.out.println(this.getName() + "在做美味的" + oats.mate + "燕麦");
               System.out.println(oats.mate + "燕麦做好啦");
               count--;
               oats.flag = true;
               System.out.println("快来吃"+oats.mate+"燕麦");
               oats.notify();
           }
        }
    }
}

测试类

package com.aa.test.useThread;

public class Test {
    public static void main(String[] args) {
        Oats oats = new Oats();
        Chef chef = new Chef("厨师", oats);
        Baby baby = new Baby("宝宝", oats);
        chef.start();
        baby.start();
    }
}

效果
在这里插入图片描述

Lambda表达式

public class Demo02LambdaRunnable {
    public static void main(String[] args) {
        new Thread(()> System.out.println("多线程任务执行!")).start(); // 启动线程         
    }
}

核心代码

()> System.out.println("多线程任务执行!")
  • 前面的一对小括号即 run 方法的参数(无),代表不需要任何条件;
  • 中间的一个箭头代表将前面的参数传递给后面的代码;
  • 后面的输出语句即业务逻辑代码

格式

(参数类型 参数名称) ‐> { 代码语句 }

例子

1.有参数和返回值时
计算器接口

package com.aa.test.Lambda;

public interface Calculator {
    int calc(int a,int b);
}

实现

package com.aa.test.Lambda;

public class Test {
    public static void main(String[] args) {
        invokeCalc(120,130,(int a,int b)->{//只有一条语句时,{}可省略
                                           //如果只有一个变量,()可省略
            return a+b;
        });
    }

    private static void invokeCalc(int a,int b,Calculator calculator){
        int result=calculator.calc(a,b);
        System.out.println("结果是"+result);
    }
}

使用前提

  1. 使用Lambda必须具有接口,且要求接口中有且仅有一个抽象方法。 无论是JDK内置的 RunnableComparator 接口还是自定义的接口,只有当接口中的抽象方法存在且唯一 时,才可以使用Lambda。
  2. 使用Lambda必须具有上下文推断。 也就是方法的参数或局部变量类型必须为Lambda对应的接口类型,才能使用Lambda作为该接口的实例。

备注:有且仅有一个抽象方法的接口,称为“函数式接口”

InputSteam字节流和Reader字符流

-输入流输出流
字节流InputStreamOutputStream
字符流ReaderWriter

当使用FileInputStream读取文本文件时,可能会有一个小问题。就是遇到中文字符时,可能不会显示完整的字符,那是因为 一个中文字符可能占用多个字节存储,所以有字符流,专用于处理文本文件。

  • 字符流:以字符为单位读写数据,专门用于处理文本文件,只能操作文本文件

注意:FlieWriter关闭资源时,与FileOutputStream不同.如果不关闭,数据只是保存到缓冲区,并未保存到文件。
因为内置缓冲区的原因,如果不关闭输出流,无法写出字符到文件中。但是关闭的流对象,是无法继续写出数据 的。如果我们既想写出数据,又想继续使用流,就需要 flush 方法。

flush :刷新缓冲区,流对象可以继续使用。
close :先刷新缓冲区,然后通知系统释放资源。流对象不可以再被使用了。

Properties 属性类

public Object setProperty(String key, String value) : 保存一对属性。
public String getProperty(String key) :使用此属性列表中指定的键搜索属性值。
public Set<String> stringPropertyNames() :所有键的名称的集合

BufferedInputStream字节缓冲流和 BufferedReader字符缓冲流

在创建流对象时,会创建一个内置的默认大小的缓冲区数组,通过缓冲区读写,减少系统IO 次数,从而提高读写的效率。

缓冲流读写方法与基本的流一致

字符缓冲流的特有方法
字符缓冲流的基本方法与普通字符流调用方式一致
public String readLine() : 读一行文字
public void newLine() : 写一行行分隔符,由系统属性定义符号

InputStreamReader转换流

Reader的子类,是从字节流到字符流的桥梁。它读取字节,并使用指定的字符集将其解码为字符。它的字符集可以由名称指定,也可以接受平台的默认字符集。

InputStreamReader(InputStream in) : 创建一个使用默认字符集的字符流
InputStreamReader(InputStream in, String charsetName): 创建一个指定字符集的字符流在这里插入图片描述

ObjectOutputStream序列化流

将Java对象的原始数据类型写出到文件,实现对象的持久存储。
public ObjectOutputStream(OutputStream out): 创建一个指定OutputStream的ObjectOutputStream
序列化:用一个字节序列可以表示一个对象,该字节序列包含该对象的数据对象的类型对象中存储的属性 等信息。字节序列写出到文件之后,相当于文件中持久保存了一个对象的信息。
反之,该字节序列还可以从文件中读取回来,重构对象,对它进行反序列化。 对象的数据对象的类型对象中存储的数据信息,都可以用来在内存中创建对象。
在这里插入图片描述
一个对象要想序列化,必须满足两个条件:

  • 该类必须实现 java.io.Serializable 接口, Serializable 是一个标记接口,不实现此接口的类将不会使任何状态序列化或反序列化,会抛出 NotSerializableException
  • 该类的所有属性必须是可序列化的。如果有一个属性不需要可序列化的,则该属性必须注明是瞬态的,使用 transient 关键字修饰

对于JVM可以反序列化对象,它必须是能够找到class文件的类。如果找不到该类的class文件,则抛出一个 ClassNotFoundException 异常
当JVM反序列化对象时,能找到class文件,但是class文件在序列化对象之后发生了修改,那么反序列化操 作也会失败,抛出一个 InvalidClassException 异常。发生这个异常的原因如下

  • 该类的序列版本号与从流中读取的类描述符的版本号不匹配
  • 该类包含未知数据类型
  • 该类没有可访问的无参数构造方法
    Serializable 接口给需要序列化的类,提供了一个序列版本号。 serialVersionUID 该版本号的目的在于验证序列化的对象和对应类是否版本匹配

PrintStream打印流

网络编程

TCP

传输控制协议 (Transmission Control Protocol)。TCP协议是面向连接的通信协议,即传输数据之前, 在发送端和接收端建立逻辑连接,然后再传输数据,它提供了两台计算机之间可靠无差错的数据传输。
三次握手:TCP协议中,在发送数据的准备阶段,客户端与服务器之间的三次交互,以保证连接的可 靠。

  • 第一次握手,客户端向服务器端发出连接请求,等待服务器确认。
  • 第二次握手,服务器端向客户端回送一个响应,通知客户端收到了连接请求。
  • 第三次握手,客户端再次向服务器端发送确认信息,确认连接。整个交互过程如下图所示:
    在这里插入图片描述

完成三次握手,连接建立后,客户端和服务器就可以开始进行数据传输了。由于这种面向连接的特性,TCP协议可以保证传输数据的安全,所以应用十分广泛,例如下载文件、浏览网页等。

UDP

用户数据报协议(User Datagram Protocol)。UDP协议是一个面向无连接的协议。传输数据时,不需要建立连接,不管对方端服务是否启动,直接将数据、数据源和目的地都封装在数据包中,直接发送。每个 数据包的大小限制在64k以内。它是不可靠协议,因为无连接,所以传输速度快,但是容易丢失数据。日常应用中,例如视频会议、QQ聊天等。

IP地址

指互联网协议地址(Internet Protocol Address),俗称IP。IP地址用来给一个网络中的计算机设 备做唯一的编号。

端口号

用于标识进程

利用 协议 + IP地址 + 端口号 三元组合,就可以标识网络中的进程了,进程间的通信可以利用这个标识与其它进程进行交互。

简单的TCP通信分析

  1. 【服务端】启动,创建ServerSocket对象,等待连接。
  2. 【客户端】启动,创建Socket对象,请求连接。
  3. 【服务端】接收连接,调用accept方法,并返回一个Socket对象。
  4. 【客户端】Socket对象,获取OutputStream,向服务端写出数据。
  5. 【服务端】Scoket对象,获取InputStream,读取客户端发送的数据。

到此,客户端向服务端发送数据成功。
在这里插入图片描述
自此,服务端向客户端回写数据。

  1. 【服务端】Socket对象,获取OutputStream,向客户端回写数据。
  2. 【客户端】Scoket对象,获取InputStream,解析回写数据。
  3. 【客户端】释放资源,断开连接。

函数式接口

有且仅有一个抽象方法的接口
@FunctionalInterface:一旦使用该注解来定义接口,编译器将会强制检查该接口是否确实有且仅有一个抽象方法,否则将会报错。需要注意的是,即使不使用该注解,只要满足函数式接口的定义,这仍然是一个函数式接口,使用起来都一样。

Lambda的延迟执行

有些场景的代码执行后,结果不一定会被使用,从而造成性能浪费。而Lambda表达式是延迟执行的,这正好可以 作为解决方案,提升性能。

Supplier接口

仅包含一个无参的方法: T get() 。用来获取一个泛型参数指定类型的对象数据

Consumer接口

Supplier接口相反,不是生产一个数据,而是使用一个数据, 其数据类型由泛型决定
包含抽象方法 void accept(T t) ,意为使用一个指定泛型的数据

Predicate接口

用于对某种类型的数据进行判断,从而得到一个boolean值结果

Function接口

用来根据一个类型的数据得到另一个类型的数据
中主要的抽象方法为: R apply(T t) ,根据类型T的参数获取类型R的结果

Stream流

import java.util.List;

public class Main {
  public static void main(String[] args) {
    List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
    int sum = numbers.stream()
        .filter(n -> n % 2  == 1)//奇数
        .map(n  -> n * n)//平方
        .reduce(0, Integer::sum);//累加

    System.out.println(sum);
  }

结果为:35

Junit

用于单元测试

反射:框架设计的灵魂

将类的各个组成部分封装为其他对象,这就是反射机制
好处:
1. 可以在程序运行过程中,操作这些对象
2. 可以解耦,提高程序的可扩展性

注解

  • 定义:注解(Annotation),也叫元数据。一种代码级别的说明。它是JDK1.5及以后版本引入的一个特性,与类、接口、枚举是在同一个层次。它可以声明在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元素进行说明,注释。
    • 概念描述:
      • JDK1.5之后的新特性
      • 说明程序的
      • 使用注解:@注解名称
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值