Java基础总复习

问题

多线程

1、谈谈对进程、线程、程序的理解

程序(program):为完成特定任务,用某种语言编写的一组指令的集合,一段静态的代码。

进程:正在运行的程序,进程作为资源分配的单位。

线程:程序内部的一条执行路径

2、代码完成继承Thread的方式创建分线程

3、代码完成实现Runnable接口的方法创建分线程

4、对比两种创建方式

* 多用接口实现Runnable
* 只能继承一个父类
*
* 联系
* Thread类本身实现了runnable接口
* 都要重写run方法,将要执行的逻辑声明在run方法中

5、Thread常用方法

* start()
* run()
* currentThread():静态方法,返回当前代码的线程
* getName():获取当前线程的名字
* setName():设置当前线程的名字
* yield():切换线程,释放当前cpu执行权
* join():在线程a中调用b的join()方法,线程a进入阻塞状态,直到线程B完全执行完之后,才结束阻塞状态
* sleep()
* isAlive();
*
*
* setPriority();
* getPriority();

6、线程的通信

wait() notify() notifyAll()

7、线程的生命周期

新键------》就绪-------》运行---------》阻塞 sleep() join(a); wait();

​ |-----------》死亡

8、线程同步

/**
 * 出现重票和错票
 * 线程不安全
 * 出现的原因:
 * 当某个线程尚未完成时,其他线程参与进来。
 *
 * 如何解决?
 * 当一个线程,当操作ticket时,其他线程不能进来,直到操作完,其他线程才可以参与进来。
 *
 * 在java中,我们通过同步机制
 * 1、同步代码快
 * synchronized(同步监视器){
 *     需要被同步的代码
 * }
 * 说明:操作共享数据的代码,即需要被同步的代买
 *      共享数据:多个线程共同操作的数据
 *      本问题中的ticket
 *      同步监视器:俗称锁
 *      任何一个对象都可以充当锁/多个线程都必须用同一把锁
 * 2、同步方法
 *      如果操作共享数据的代码完整的生命在一个方法中,我们不妨将此方法设置为同步
 *
 * 同步的方式
 * 好处
 * 1、解决了线程安全问题
 * 坏处
 * 1、变慢了,只有一个线程参与,其他线程等待,相当于单线程问题
 */

/**
 * 使用同步方法解决实现Runnable接口的线程安全问题
 *          关于同步方法的总结
 *          1、同步方法仍然设计到同步监视器
 *          2、非静态的同步方法,同步监视器是 this
 *              静态的同步方法,同步监视器是:当前类本身
 */

9、单例模式之懒汉式

    public static synchronized Bank getInstance()
    {
        //方式一:效率稍差
//        synchronized(Bank.class){
//            if (instance == null) {
//                instance = new Bank();
//            }
//            return instance;
//        }
        //方式二:效率更高
        if(instance == null){
            synchronized(Bank.class){
                if (instance == null) {
                    instance = new Bank();
                }
            }
        }
        return instance;
    }

10、死锁问题

  • 不同的线程分别占用对方需要的同步资源不放弃,都在等待对方放弃自己需要的同步资源,就形成了线程的死锁
  • 出现思索后,不会出现异常提示,知识所有的线程都处于阻塞状态,无法继续

解决方法

  • 专门的算法、原则
  • 尽量减少同步资源的定义
  • 尽量避免嵌套同步
11、Lock(锁)
class Window implements Runnable
{
    private int ticket = 100;

    //实例化 Reentrantlock
    private ReentrantLock lock = new ReentrantLock();
    @Override
    public void run() {
        while(true)
        {
            try {
                if (ticket > 0) {
                    //调用lock()
                    lock.lock();
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + "   " + ticket);
                    ticket--;
                } else
                    break;
            }
            finally {
                //解锁
                lock.unlock();
            }
        }
    }
}
12synchronized 与 lock异同?

都是解决线程安全问题

不同

lock 是手动的锁定(lock),手动的解锁(unlock)

synchoronized,在执行完相应的代码逻辑以后自动的解锁。

选择

lock手动方式更加灵活

优先用Lock ------》同步代码块-------》同步方法

13、如何姐姐线程安全问题

lock 、 synchoronized

14、存钱
/**
 * 银行有一个账户,有两个出乎分别向同一账户转入3000, 1000, 存3次,每次存完打印账户
 *
 *
 * 分析
 * 1、是否多线程 是
 * 2、是否有共享数据   有,账户
 * 3、是否有线程安全问题? 有 需要考虑如何解决线程安全问题,同步机制:有
 */

class Account{
    private double balance;


    public Account(double balance) {
        this.balance = balance;
    }

    //存钱
    public synchronized void deposit(double amt){
        if(amt > 0)
        {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            balance += amt;
            System.out.println(Thread.currentThread().getName() + "存钱成功,余额为" + balance);
        }
    }
}

class Customer  extends Thread{
    private Account account;

    public Customer(Account acct){
        this.account = acct;
    }

    @Override
    public void run() {
        for(int i = 0;i < 3; i++)
        {
            account.deposit(1000);
        }
    }
}

public class AccountTest
{
    public static void main(String[] args) {
        Account acct = new Account(0);
        Customer c1 = new Customer(acct);
        Customer c2 = new Customer(acct);

        c1.setName("甲");
        c2.setName("乙");

        c1.start();
        c2.start();
    }
}
15、使用两个线程打印1-100。线程1,2交替打印
/**
 * 设计到的三个方法
 *
 * wait():一旦执行此方法,当前线程进入阻塞状态,并释放同步监视器
 * notigy(): 一旦执行此方法,就会唤醒被wait的线
 * notifyAll():唤醒所有
 *
 * 说明
 * 1、wait   notify notifyAll只能出现在同步方法,或者在同步代码块中(lock都不行)
 * 2、省略this
 * 3、三个方法的调用者必须使同步方法或者是同步方法中的同步监视器。
 * 4、三个方法是定义在object类中的
 *          否则会出现异常。
 */
class Number implements Runnable
{
    private int number = 1;
    @Override
    public void run() {
        while(true)
        {
            synchronized (this) {
                //
                notify();
                if (number < 100) {
                    System.out.println(Thread.currentThread().getName() + "  " + number);
                    number++;

                    try {
                        //使得调用wait()方法的线程进入阻塞状态
                        wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                } else
                    break;
            }
        }
    }
}
public class CommunicationTest
{
    public static void main(String[] args) {
        Number number = new Number();
        Thread thread = new Thread(number);
        Thread thread2 = new Thread(number);

        thread.start();
        thread2.start();
    }
}
16、面试题 sleep()和wait()方法异同

同:

一旦执行方法,都可以使当前线程进入阻塞状态

不同:

1、两个方法声明的位置不同:Thread类中声明sleep(), Object()类中声明wait();

2、调用范围不同:sleep()可以在任何需要的场景调用

​ wait()必须使用在同步代码块或者同步方法中;

3、关于是否释放同步监视器的问题:如果两个方法都使用在同步代码块或者同步方法中,

​ sleep方法不会释放同步监视器

​ wait()会释放同步监视器

17、生产者/消费者问题

生产者将产品交给店员,消费者取走产品,店员一次只能持有固定的产品,

package com.zhou.java2;

/**
 * 生产者消费者问题
 *
 * 是否使多线程  是  生产和线程   消费者线程
 * 是否有共享数据  是   产品
 * 是否有线程冲突问题   是   产品数量
 * 是否涉及到线程通信  是;
 *
 */
class  Clerk{
    private int productCount = 0;
    //生产产品
    public synchronized void produceProduct() {
        if(productCount < 20)
        {
            productCount++;
            System.out.println(Thread.currentThread().getName() + "生产铲平" + productCount);
            notify();
        }
        else
        {
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    //消费产品
    public synchronized void consumerProduct() {
        if(productCount > 0)
        {
            System.out.println(Thread.currentThread().getName() + "消费铲平"+ productCount);
            productCount--;
            notify();
        }
        else
        {
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

class Producer extends Thread{
    private Clerk clerk;

    public Producer(Clerk clerk){
        this.clerk = clerk;
    }
    @Override
    public void run() {
        System.out.println(getName() + ":开始生产");

        while(true){
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            clerk.produceProduct();
        }
    }
}

class Consumer extends  Thread{
    private Clerk clerk;

    public Consumer(Clerk clerk){
        this.clerk = clerk;
    }

    @Override
    public void run() {
        System.out.println(getName() + ":开始消费");

        while(true){
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            clerk.consumerProduct();
        }
    }
}
public class ProductTest
{
    public static void main(String[] args) {
        Clerk clerk = new Clerk();

        Producer producer = new Producer(clerk);
        Consumer consumer = new Consumer(clerk);

        producer.start();
        consumer.start();
    }
}
18、实现Callable接口

重写call方法,可以有返回值

方法可以抛出异常

支持泛型的返回值

需要借助FutureTask类,比如获取返回结果。

Future接口

可以对具体Runnable、Callable任务的执行结果进行取消、查询是否完成、获取结果等

FutureTask是Future接口的唯一实现类

如何理解比Runnable强大

call()可以抛异常

可以有返回值

callable可以支持泛型

package com.zhou.java2;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;

/**
 * 船舰线程的方式三:实现Callable接口  jdk5.0新增
 *
 */

//创建一个实现Callable的实现类
class NunThread implements Callable{
    //将执行的逻辑放入call方法中
    @Override
    public Object call() throws Exception {
        Integer sum = 0;
        for(int i = 0; i < 100; i ++)
        {
            if(i % 2 == 0)
            {
                System.out.println(i);
                sum += i;
            }
        }
        return sum;
    }
}
public class ThreadNew {
    public static void main(String[] args) {
        //创建实现类对象
        NunThread n = new NunThread();
        //将实现类对象放入FutureTask中
        FutureTask futureTask = new FutureTask(n);
        //将FutureTaks的对象作为参数传递到Thread类的构造器中。
        new Thread(futureTask).start();
        try {
            //get方法的返回值即为futureTask构造器参数Callable实现类call的返回值
            Object o = futureTask.get();
            System.out.println("总和为" + o);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }
}
19、使用线程池

思路:提前创建好多个线程,放入线程池中,使用的时候直接获取,使用完就放回。

好处:

  • 提高相应速度(减少了创建新线程的时间)
  • 降低资源消耗(重复利用线程池中线程,不需要每次都创建)
  • 便于线程管理
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
/**
 * 创建线程的方式4:使用线程池
 */
class NumberThread implements Runnable{
    @Override
    public void run() {
        for(int i = 0; i <= 100; i++){
            if(i % 2 == 0)
                System.out.println(i);
        }
    }
}

class NumberThread1 implements Runnable{
    @Override
    public void run() {
        for(int i = 0; i <= 100; i++)
        {
            if(i % 2 == 0)
                System.out.println(i);
        }
    }
}

public class ThreadPool {
    public static void main(String[] args) {
        //提供指定线程数量的线程池
        ThreadPoolExecutor executorService = (ThreadPoolExecutor) Executors.newFixedThreadPool(10);

        //设置线程池的属性
        executorService.setCorePoolSize(15);
        executorService.setMaximumPoolSize(19);

        //适合使用于Runnable
        //执行指定的线程操作,需要提供实现Runnable接口
        executorService.execute(new NumberThread());
        executorService.execute(new NumberThread1());

        //关闭线程池
        executorService.shutdown();
        //适合适用于Callable
        //executorService.submit();
    }
}
20、面试题 创建多线程有几种方式

4种 继承Thread 实现Runnable 实现Callable 线程池

21、释放锁操作
  • 正常结束
  • break return
  • 异常
  • wait()
22、不会释放
  • sleep() yield()
  • suspend()

Java常用类

23、String

String 是一个final类,代表不可变的字符序列

实现了Serializable接口:表示字符串是支持序列化的;

实现了Comparable接口:可以比较大小的

定义了final char[] value 用于存储字符串数据

  • 当对字符串重新赋值时,需要重写指定的内存区域,不能对原有的直接修改

  • 当现有的字符串进行操作时,也需要重新指定区域进行赋值

  • 通过字面量的方式给一个字符串,此时的字符串的值声明在常量池中

补充

方法区(包含字符串常量池)栈和堆

public class stringTest{    public static void main(String[] args) {        String s1 = "abc";        String s2 = "abc";        String s3 = "abc";        s3 += "def";        System.out.println(s2);        System.out.println(s3);        System.out.println();        String s4 = "abc";        String s5 = s4.replace('a', 'm');        System.out.println(s4);        System.out.println(s5);    }}
String 赋值
String str = "hello";String s1 = new String();String s2 ]= new String(String original);String s3 = new String(char[] a);String s4 = new String(char[] a, int startIndex, int count);
面试题

String str1 = “abc” 和 Strinh str2 = new String(“abc”); 有什么区别?

String s1 = "javaEE";
String s2 = "javaEE";

String s3 = new String("javeEE");
String s4 = new String("javaEE");

System.out.println(s1 == s2);//true
System.out.println(s3 == s4); //false;

Person p1 = new Person("Tom", 12);
Person p2 = new Person("Tom", 12);

System.out.println(p1.name == p2.name);//true

//结论
//常量与常量的拼接结果在常量池。且常量池中不会存在相同内容的常量
//只要其中有一个是变量,结果就在堆中
String s1 = "javaEE";
String s2 = "hadoop";

String s3 = "javaEEhadoop";
String s4 = "javaEE" + "hadoop";
String s5 = s1 + "hadoop";
String s6 = "javaEE" + s2;
String s7 = s1 + s2;

//有变量名参与,都在堆空间开辟,相当于new
String.out.println(s3 == s4); //true
String.out.println(s3 == s5); //false
String.out.println(s3 == s6); //false
String.out.println(s3 == s7); //false
String.out.println(s5 == s6); //false
String.out.println(s5 == s7); //false
String.out.println(s6 == s7); //false

String s8 = s5.intern();
System.out.println(s3 == s8);//true

//常量跟常量的拼接在常量池
//final 是常量
final String s9 = "javaEE";
String s10 = s9 + "hapoop";
System.out.println(s3 == s5); //true
面试题
String str = new String("good");
char[] ch = {'t', 'e', 's', 't'};
public void change(String str, char ch[])
{
    //不可变,不影响
    str = "test ok";
    ch[0] = 'b';
}

public static void main(String[] args)
{
    StringTest ex = new StringTest();
    
    ex.change(ex.str, ex.ch);
    System.out.println(ex.str);  //good
    System.out.pribtln(ex.ch);   //best
}
24、jvm Heap堆

一个jvm实例只存在一个堆内存,堆内存的大小

  • 新生区
  • 养老区
  • 永久区(虽然jvm规范将方法区描述为堆的一个逻辑部分,但它还有一个别名叫非堆,目的就是要和堆分开)

字符串常量池在jdk1.6在方法区 1.7在堆中 1.8在方法区

25、String常用方法
String s1 = "helloworld";
System.out.println(s1.length());
System.out.println(s1.charAt(0));
System.out.println(s1.isEmpty());
System.out.println(s1.toLowerCase());
System.out.println(s1.toUpperCase());

String s2 = s1.trim();   //删除两端空格

s1.equalsIgnoreCase(s2);  //忽略大小写

String s4 = s1.concat("def");//连接

String s5 = s1.substring(1);




endsWith(String suffix); //判断结尾
startWith(String prefix);//判断开头
startWith(String prefix, int toffset);//判断开头,指定位置

boolean contains(CharSequence s);   //是否半酣此字符串
int indexOf(String str); //是否半酣,并返回索引
int lastIndexOf(String str);

String replace(char oldChar, char newChar);
String replace(CharSequence target, CharSequence replacement);
String replaceAll(String regex, String replacement); //正则表达式
String replaceFirst(String regex, String replacement);

String[] split(String regex);
26、String转换问题
String  str1 = "123";// int num = (int) str1;错误int num = Integer.parseInt(str1);//基本数据类型转换成StringString str2 = String.valueOf(num);String str3 = num + "";//String 转换  char[]String str4 = "abc";char[] charArray = str4.toCharArray();String str4 = new String(charArray);
String str1 = "abc123";char[] charArray = str1.toCharArray();reverse(charArray, 0, 2);str1 = new String(charArray);
  • String 与byte[] 之间的转化吧
String str1 = "abc123";
//String 转 byte[]    getBytes();
byte[] b = str1.getBytes();
System.out.println(Arrays.toString(b));

String str2 = "abc123中国";
byte[] bytes = str2.getBytes();//使用默认的字符集进行转化
System.out.println(Arrays.toSstring(bytes));//中文对应三个

byte[] bytes2 = str2.getBytes("gbk");//使用gbk编码格式
System.out.println(Arrays.toString(bytes2));//中文对应gbk两个


//逆过程  解码
String str3 = new String(bytes);
System.out.println(str3);   //没毛病

String str4 = new String(bytes2);
System.out.println(str4);   //出现乱码,解码编码格式不一样

String str5 = new String(bytes2, "gbk");
System.out.println(str5);   //没有出现乱码,没毛病
27、编码解码

编码:字符串----》字节

解码:字节-----》字符串

28、常见算法题目
29、StringBuffer和StringBuilder

String StringBuffer StringBuilder异同

String:不可变的字符序列, 底层都用char[]数组存储

StringBuffer:可变的字符序列;效率低,线程安全

StringBuilder:可变的字符序列 1.5 线程不安全,效率高

如何选择?

是否是多线程问题 多线程用StringBuffer

StringBuffer sb1 = new StringBuffer();//char[] value = new char[16];sb1.append('a');//value[0] = 'a';sb1.append('b'); //value[1] = 'b';StringBuffer sb2 = new StringBuffer("abc");//char[] value = new char["abc".length() + 16];
问题1、

sb1.length() = 2;

sb2.length9) = 3;

问题2

扩容问题:如果要添加的数据底层数组盛不下了,那就扩容数组

开发中建议使用StringBuffer(int capacity) 构造器,避免扩容,复制

30、StringBuffer方法
StringBuffer s1 = new StringBuffer("abc");s1.append(1);s1.append('1');System.out.println(s1);s1.delete(2, 4);System.out.println(s1);  //ab1s1.replace(2, 4, "hello");s1.insert(2, false)

总结:

增:append()

删:delete(); setChart

改:replace

查:charAt(int n);

插:insert(int offset, xxx)

长度:length();

遍历:for() + charAt()//toString();

31、String StringBuffer StringBuilder效率对比

StringBuilder快于StringBuffer.>>>>>>>>>>String

32、jdk8之前日期时间API
public class DateTimeTest{    /**     * java.util.Date类     *            |----java.sql.Date     * 1、两个构造器的使用     *     * 2、两个方法的使用     * toString():显示当前年月日时分秒     * getTime():获取当前Date对象对应的毫秒数     *     * 3、java.sql.Date对应数据库中的日期类型变量     * 》如何实例化     * 》sql.Date ---->  util.Date   直接赋值就行     */    @Test    public void test2()    {        //创建了一个当前时间的Date对象        Date date1 = new Date();        System.out.println(date1.toString());        System.out.println(date1.getTime());        //构造器二:创建指定毫秒数的date对象        Date date2  = new Date(date1.getTime());        System.out.println(date2.toString());    }    //System类中的currentTimeMillis();    @Test    public void test1()    {        long time = System.currentTimeMillis();        //1970 1 1 到现在的毫秒数        //称为时间戳        System.out.println(time);    }}
SimpleDateFormate

Date类的Api不宜与国际化,大部分被废弃了

public void testSimpleDateFormat() throws ParseException {        SimpleDateFormat sdf = new SimpleDateFormat();        Date date = new Date();        System.out.println(date);        //格式转化        String format = sdf.format(date);        System.out.println(format);        //格式化的逆过程      字符串----》日期        String str = "2021-1-1 上午11:43";        Date date1 = sdf.parse(str);        System.out.println(date1);                //指定方式进行格式化        new SimpleDateFormat("yyyy-MM-dd");    }
Calendar 日历类
public void testCalender(){    //实例化    //方式一:创建其子类的对象    //方式二:调用其静态方法    Calendar calendar = Calendar.getInstance();    System.out.println(calendar.getClass());    //2、常用方法    //get    //当前这个日期是这个月的第几天    //月份从0开始    int days = calendar.get(Calendar.DAY_OF_MONTH);    //set    //修改日期    calendar.set(Calendar.DAY_OF_MONTH, 22);    //add()、    calendar.add(Calendar.DAY_OF_MONTH, 11);    //getTime()    Date time = calendar.getTime();    //setTime()    calendar.setTime(time);}
jdk8中新日期详见40
33、如何理解String的不可变性

每次改变都会新造一个String

34、模拟一个trim方法,去除字符串两端的空格
35、将一个字符串进行反转,将字符串指定部分进行反转
public String reverse(String str, int startIndex, int endIndex){    if(str == null || str.length() == 0)        return str;    char[] arr = str.toCharArray();    for(int x = startIndex, y = endIndex;x < y;x++,y--)    {        char temp = arr[x];        arr[x] = arr[y];        arr[y] = temp;    }    return new String(arr);}//方式2:使用String拼接操作public String revese1(String str, int startIndex, int endIndex){    String reveseStr = str.substring(0, startIndex);    for(int i = endIndex; i >= startIndex; i--)    {        reveseStr += str.charAt(i);    }    reveseStr += str.substring(endIndex + 1);}
36、获取一个字符串,在另一个字符串中出现的次数
public int getCount(String mainStr, String subString)
{
    int mainlength = mainStr.length();
    int subLength = subString.length();

    if(mainlength >= subLength)
    {
        int count = 0;
        int index = 0;
        while(true)
        {
            if((index = mainStr.indexOf(subString)) != -1)
            {
                count ++;
                mainStr = mainStr.substring(index + 1);
            }
            else
                break;
        }
        return count;
    }
    else
        return 0;
}


public int getCount(String mainStr, String subString)
    {
        int mainlength = mainStr.length();
        int subLength = subString.length();

        if(mainlength >= subLength)
        {
            int count = 0;
            int index = 0;
            while((index = mainStr.indexOf(subString, index + 1)) != -1)
            {
                count ++;
                index ++;
            }
            return count;
        }
        else
            return 0;
    }
37、获取两个字符串中的最大相同子串
public String get(String str1, String str2){    String maxStr = str1.length() >= str2.length() ? str1 : str2;    String minStr = str1.length() < str2.length() ? str1 : str2;        int length = minStr.length();        for(int i = 0; i < length; i++)    {        for(int x = 0, y = length - i;y <= length;x++,y++)        {            String subStr = minStr.substring(x, y);            if(maxStr.contains(subStr)){                return subStr;            }        }    }}
39、代码阅读
public void testStringBuffer(){    String str = null;    StringBuffer sb = new StringBuffer();    sb.append(str);//        System.out.println(sb.length());4        System.out.println(sb); //"null"        StringBuffer sb1 = new StringBuffer(str);   //抛异常NullPointException        System.out.println(sb1);}
40、jdk8中新日期时间API

Calender比Date有不少改进 但是有很多问题

  • 可变性:像日期和时间这样的类应该是不可变的
  • 偏移性:Date的开始日期,年份是从1900开始,月份是从0开始的
  • 格式化只对Date有用,Calendar则不行

此外不是线程安全的,不能处理闰秒等;

引入java.time包

包含本地日期(LocalDate) 本地时间(LocalTime)、本地日期时间(LocalDateTime)、时区(ZonedDateTime)和持续时间(Duration)的类

Date类中也加入了方法转换

public void LocalDateTest(){
    //LocalDate  LocalTime,  LocalDateTime
    LocalDate localDate = LocalDate.now();
    LocalTime localTime = LocalTime.now();
    //使用频率高
    LocalDateTime localDateTime = LocalDateTime.now();

    System.out.println(localDate);
    System.out.println(localTime);
    System.out.println(localDateTime);

    //设置指定的年月日没有偏移量
    LocalDateTime localDateTime1 = LocalDateTime.of(2020, 10, 6, 13, 23, 34);
    System.out.println(localDateTime1);

    //都有这个方法  getxxx
    System.out.println(localDateTime.getDayOfMonth());
    System.out.println(localDateTime.getDayOfWeek());
    System.out.println(localDateTime.getDayOfYear());
    System.out.println(localDateTime.getMonth());
    System.out.println(localDateTime.getMonthValue());
    System.out.println(localDateTime.getMinute());

    // 都有withxxx
    LocalDate localDate1 = localDate.withDayOfMonth(22);
    System.out.println(localDate1);
    System.out.println(localDate); //不可变性,本身不该,都是这样的

    //plus  不可变性
    LocalDateTime localDateTime2 = localDateTime.plusMonths(3);
    
    //minus......
}
41、瞬时Instant

时间线上的一个瞬间点。这可能被用来记录应用程序中的时间戳。

从1970.1.1开始。

类似于Date

@Test
public void test2()
{
    Instant instant = Instant.now();
    //东加西减,本初子午线时间
    System.out.println(instant);

    //设置到东八区的时间
    OffsetDateTime offsetDateTime = instant.atOffset(ZoneOffset.ofHours(8));
    System.out.println(offsetDateTime);

    //计算毫秒数多少
    long l = instant.toEpochMilli();//获取到现在的毫秒数
    System.out.println(l);

    //可以通过毫秒数设置时间
    Instant instant1 = Instant.ofEpochMilli(111111L);
    System.out.println(instant1);
}
42、DateTimeFormatter:格式化或解析日期

类似于SimpleDateFormat

public void test3()
{
    //方式一:预定义标准格式;如下
    DateTimeFormatter isoLocalDateTime = DateTimeFormatter.ISO_LOCAL_DATE_TIME;
    //格式化
    String format = isoLocalDateTime.format(LocalDateTime.now());
    System.out.println(format);
    //解析
    TemporalAccessor parse = isoLocalDateTime.parse(format);
    System.out.println(parse);

    //方式二:本地化方式,ofLocalLizedDateTime();
    //参数  FormatStyle.LONG   FormatStyle.MEDIE  / FormatStyle.SHORT
    DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.LONG);
    String format1 = dateTimeFormatter.format(LocalDateTime.now());
    System.out.println(format1);
    //ofLocalLizedDate()多了个参数  FormatStyle.FULL;

    //方式三:自定义的格式。如:“yyyy-MM-dd hh-mm-ss";
    //重点
    //重点
    //重点
    DateTimeFormatter dateTimeFormatter1 = DateTimeFormatter.ofPattern("yyyy-MM-dd hh:mm:ss");
    String format2 = dateTimeFormatter1.format(LocalDateTime.now());
    System.out.println(format2);
}
43、Comparable接口的使用
//Comparable使用举例String[] arr = new String[]{"AA", "CC", "MM"};Arrays.sort(arr);System.out.println(arr);/*重写规则当前this大于obj  返回正整数       等于      0       小于      负数*/
  • 自定义类实现Comparable接口
public class Goods implements Conparable{    private String name;    private int a;        //加个从低到高排序    @Override    public void compareTo(Object o)    {        if(o instanceof Goods){            Goods goods = (Goods) o;            if(this.price > goods.price){                return 1;            }            else if(this.price < goods.price)                return -1;            else                return 0;        }        throw new Exception();    }}public void test2();{    Goods[] arr = new Goods[4];    arr[0] = new Good("lianxiangMous", 30);    arr[0] = new Good("xiangMous", 30);    arr[0] = new Good("lianMous", 30);    arr[0] = new Good("lianxiang", 30);}
44、定制排序:Comparator
//背景
//当元素类型没有实现Comparable接口
//实现了了Comparable接口,但不适合
//可以考虑使用定制的Comparator

//重写comparator() 有连个参数
public void test()
{
    String[] arr = new String("AAA", "ccc");
    Arrays.sort(arr, new Comparator(){
        @Override
        public int compare(Object o1, Object o2)
        {
            if(o1 instanceof String &&
              o2 instanceof String)
            {
                String s1 = (String) o1;
                String s2 = (String) o2;
                return -s1.compareTo(s2);
            }
            throw new RuntimeException("输入类型不一致");
        }
    })
}


public void test4()
{
    Goods[] arr = new Goods[5];
    
    
    .....;
    Arrays.sort(arr, new Comparator(){
        @Override
        public int compare(Object o1, Object o2)
        {
            if(o1 instanceof Goods && o2 instanceof Goods)
            {
                Goods g1 = (Goods)o1;
                Goods g2 = (Goods) o2;
                if(g1.getName().equlas(g2.getName()))
                {
                	return -Double.compare(g1.getPrice, g2.getPrice);
                }
                else
                    return g1.getName().compareTo(g2.getName());
            }
            return 0
        }
    })
}

对比

  • Comparable接口的方式一旦确定,在任何位置都能比较大小
  • Comparator属于临时比较
45、System类
//currenTimeMillis();
//exit();退出程序  0,表示正常退出,, 非0表示异常退出
//gc();垃圾回收器
//getProperty(String key);获取属性
/* 常用的
	"java.version"  版本
	“Java.home"   文件路径
	”os.name"   系统名称
	”os.version"  系统版本
	“user.name"  用户名称
*/
46、Math 数学类
  • abs 绝对值
  • acos, asin, atan, cos, sin, tan 单间函数
  • sqrt 开放
  • pow(double a, double b) 次幂
  • log 自然底数
  • exp e为底自然数
  • max
  • min
  • random
  • long round()
  • toDegrees 弧度—》角度
  • toRadians() 角度—》弧度
47、BigInteger

Math包下的BigInteger 可以表示不可变的任意精度的整数

Integer 2 31 - 1

Long 2 63-1

48、BigDecimal类

浮点型,高精度。任意精度

BigInteger bi = new BigInteger("123232131");
BigDecimal bd = new BigDecimal("12323213.1231");
BigDecimal bd2 = new BigDecimal("11");
bd.divide(bd2, ROUND_HALF_UP);
bd.divide(bd2, 25, ROUND_HALF_UP);
49、2017-08-16转化为java.sql.Date类对象
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
sdf.parse("2017-08-16");
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd");
50、解释何为编码?解码?何为日期时间的格式化?

编码:字符串-》字节数据

解码:字节-》字符串

格式化:日期-》字符串

解析:字符串-》日期

51、JDK8 之前和jdk8中日期、时间相关的类分别有那些

java.util.Date 和 java.sql.Date -> Instant

SimpleDateFormat -->>>> DateTimeFormatter

Calendar ------> LocalDate LocalTime LocalDateTime

51、枚举类
/** * 一、枚举类的使用 * 注意:若枚举类只有一个对象,则可以作为一种单例模式的实现方式 * * 二、如何定义枚举类 * 方式一: * jak5.0之前自定义枚举类 * 方式二: * 之后可以用enum关键字定义枚举类型 * * 三、Enum类中的常用方法 * values(); * valueof(); *  * 四、自定义枚举类实现接口 *  可以让枚举类分别实现接口中的抽象方法 */public class EnumTest {    public static void main(String[] args) {        Season1 spring = Season1.SPRING;        //values();        Season1[] values = Season1.values();        //valueof();        Season1 spring1 = Season1.valueOf("SPRING");    }}
public class EnumTest {    public static void main(String[] args) {        Season spring = Season.SPRING;    }}class Season{    //提供当前枚举类的多个对象    public static final Season SPRING = new Season("春天", "春");    public static final Season SUMMER = new Season("春天", "春");    public static final Season AUTUMN = new Season("春天", "春");    public static final Season WINTER = new Season("春天", "春");    //声明Season对象的属性    //需要private  final 修饰    private final String seasonName;    private final String seasonDesc;    //1、私有化类的构造器,并给对象书香赋值    private Season(String seasonDesc, String seasonName){        this.seasonName = seasonName;        this.seasonDesc = seasonDesc;    }    public String getSeasonName(){        return seasonName;    }    public String getSeasonDesc(){        return seasonDesc;    }}
//之后可以用enum关键字定义枚举类型
//使用enum关键字枚举类
enum Season1{
    SPRING("春天", "春"),
    SUMMER("夏天", "下");

    private final String seasonName;
    private final String seasonDesc;

    private Season1(String seasonName, String seasonDesc)
    {
        this.seasonDesc = seasonDesc;
        this.seasonName = seasonName;
    }
}
52、注解 Annotation
概述

jdk5.0新增元数据即Annotation

特殊标记,运行时被读取,并执行相应的处理,通过使用Annotation,程序员可以在不改变原有逻辑的情况下,在源文件中嵌入一些补充信息。代马分析工具、开发工具和部署工具可以通过这些补充信息进行验证或者进行部署

javase中注解比较简单,在javaee/android中注解占据了更重要的角色,。配置文件可以用注解进行替换。

JPA是基于注解的,Spring2.5以上都是基于注解的

框架 = 注解 + 反射+ 设计模式。

53、如何自定义注解
public @interface MyAnnotation {
    String value() default "hello";
}
54、基本注解
@Override

限定重写

@Deprecated

过时了,不建议使用

@SuppressWarings

抑制编译器警告

55、元注解: 修饰其他注解的注解
一般用上Retention Target
  • Retention

指定注解的声明周期

SOURCE 通过编译的时候discarded

CLASS (默认行为) 将被保留在class文件中,但不会在run的时候不会加载

RUNTIME 保留在class文件中,run时加到内存中,只有这个才能通过反射获取。

  • Target

指定被修饰注解能修饰那些数据

TYPE: class interface

FIELD

METHOD…

没写在哪里都能用

  • Documeneted

javadoc一般不包含注解信息

如果想被包含,则在注解上加这个注解

  • Inherited

继承性,如果有类用了该注解,子类就自动加上该注解

通过反射来获取注解信息
Class clazz = Student.class;
Annotation[] annotations = clazz.getAnnotations();
System.out.println(annotations);
56、元数据: 对现有数据修饰的数据

String name = “atguigu”;

​ 元数据 数据

jdk8 注解新特性
  • 可重复注解

可以重复定义多个

//以前这样public @interface MyAnnotations{    MyAnnotation[] value();}@MyAnnotations({@MyAnnotation(value = "hi")...})//jdk8之后@Repeatable(MyAnnotations.class)public @interface MyAnnotation{    MyAnnotation[] value();}
  • 类型注解
@Target({TYPE, TYPE_PARAMETER, TYPE_USE})public @interface MyAnnotation{    MyAnnotation[] value();}//可以注解泛型class Gemeric<@MyAnnotation T>{    }

JAVA集合

57、集合框架

/------Collection接口, 单列集合,用来存储一个一个对象

​ /--------List接口 元素有序、可重复 ”动态数组"

​ /--------Set接口 元素无需、不可重复 “高中集合”

/------Map接口:双列集合,一堆一对数据

​ /--------HashMap, LinkedHashMap, TreeMap

58、Collection接口中的API
@Test
public void test1()
{
    Collection coll = new ArrayList();

    //add()
    coll.add("AA");
    coll.add("bb");
    coll.add("123");

    //size()
    System.out.println(coll.size());

    //addAll()
    Collection coll2 = new ArrayList();
    coll2.add("CC");
    coll.addAll(coll2);

    //clear
    coll.clear();
    //isEmpty();
    System.out.println(coll.isEmpty());
    
    
    coll.contains(new String("aa"));
    
    coll.remove(123);
    
    Collection coll1 = Arrays.asList(123, 345);
    coll.removeAll(coll1);
    
    //求交集,结果给coll
    coll.retainAll(coll1);
    
    //判断当前集合和形参是否一样    有序
    System.out.println(coll.equals(collq));
    
    
    //hashCode();返回当前对象的hash值
    coll.hashcode();
    
    //集合转换为数组,toArray();
    Objecep[] arr = coll.toArray();
    
   	//转化成Collection
    Arrays.asList(new String[]{"ji", " aefea"});
    
    List arr1 = Arrays.asList(new Integer[]{123, 456});
    System.out.println(arr1);
    
    
    //iterator():返回Iterator接口的实例,用于遍历集合元素
}
59、集合元素的遍历 使用Iterator
//Iterator接口  迭代器接口//遍历用接口Collection coll = new ArrayList();coll.add(1223);coll.add(466);Iterator iterator = coll.iterator();System.out.println(iterator.next());//没有元素使用next() 报异常NoSychElementException();while(iterator.hasNext()){    Object obj = iterator.next();    if("Tom".equals(obj)){        iterator.remove();    }}//remove方法移除
60、List接口概述 (动态数组)
ArrayList LinkedList Vector异同

  • 都实现了List接口,存储数据的特点相同:存储有序的数据

不同

  • ArrayList:作为List接口的主要实现类,线程不安全的,效率高,底层使用Object类型数组存储
  • LinkedList: 底层使用双向链表,对于频繁插入删除操作,使用此类效率高
  • Vector:作为List接口的古老实现类,线程安全的,效率低,底层使用Object类型数组存储
61、ArrayList底层源码

JDK7情况下

ArrayList list = new ArrayList();

底层是容量为10的Object[]; 默认扩容为原容量的1.5倍

结论:建议使用代餐的构造器 new ArrayList(100);

JDK8中的变化

底层初始化为{} 并没有创建

第一次add 创建10 的容量

小结

JDK8中内存节省了, jdk7中是饿汉式 jdk8中类似于懒汉式

62、LinkedList源码分析

内部声明了 node类型的 first last 属性

Node定义为:双向链表节点

63、List接口常用操作
ArrayList list = new ArrayList();
list.add(123);
list.add(2321);

//在第一个位置插入
list.add(1, 12321);

//addAll();
List list1 = Arrays.asList(1,3,4);
list.addAll(list1);
System.out.println(list.size());


//get方法
System.out.println(list.get(0));

//indexOf();首次出现的索引位置
System.out.println(list.indexOf(123));
//lastIndexOf();找不到返回值是-1;

//remove(int i);按照索引删除

//set(int ,  Object);

//sublist;
64、Set接口:无序不可重复的

set没有额外定义新方法,使用的都是Collection中定义过的

  • HashSet:作为Set接口的主要实现类;线程不安全
    • LinkedHashSet: HashSet子类 ,指针,看似有序,按照添加顺序来遍历
  • TreeSet: 使用红黑树存的,同一个类new的对象,可以排序,可以按照添加对象的指定属性进行排序
public static void main(String[] args) {
    //1、无序性  != 随机性
    /*
    hashset底层是用数组存的
    存的值并非按照数组索引顺序添加,而是根据哈希值决定的
     */
    //2、不可重复性
    /*
    保证添加的元素按照equals()判断时,不能返回true;即相同的元素只能添加一个
     */

    

    Set set = new HashSet();
    set.add(1324);
    set.add(342);
    set.add("aa");

    Iterator iterator = set.iterator();
}
65、Map接口,双列数据,存储key-value对的数据

HashTable----》Properties; 古老的实现类,线程安全,效率低

HashMap------》LinkedHashMap: 主要实现类,线程不安全,效率高,可以存储null的Key和value

TreeMap-----》实现key-value进行排序,按照Key来排的

  • 底层使用红黑树

jdk7 数组+链表

jdk8 数组+链表+红黑树

Properties:常用来处理配置文件,key和value都是String类型

public void Maptest{    Map map = new HashMap();    //map = new HashTable();    map.put(null, null);}
66、HashMap底层实现原理
67、HashMap和Hashtable的异同

同:都是一对对数据

  • 主要实现类,线程不安全,效率高,可以存储null的Key和value
  • 古老的实现类,线程安全,效率低
68、HashMap底层实现原理;(jdk7)
HashMap map = new HashMap();//实例化以后,底层创建了一个长度为16的entry数组map.put(key1,value1);//前面已经put了//首先计算key1的hash值//如果此位置数据为空,此时添加成功,//如果不为空,意味着此位置存在一个或者多个数据,比较当前key1和已经存在的hash值//如果key1哈希值与已经存在的数据hash值都不相同,此时添加陈坤//如果key1哈希值和已经存在的某一个hash值相同,调用equals方法,//在不断的添加过程中,会涉及到扩容问题,默认扩容为原来容量的2倍,并将原有的数据赋值过来
jdk8区别
  • new HashMap() 没有创建一个长度为16的数组
  • jdk8 底层数组是node[]
  • 首次调用put()方法时,底层创建长度为16的数组
  • jdk7底层结构只有数组加链表, jdk8数组+链表+红黑树
  • 当数组的某一个索引位置上的元素以链表形式的存在的数据个数>8且当前数组的长度>64,此时此索引位置上的所有数据改为使用红黑树存储
69、Map常用方法
HashMap map = new HashMap<String, Integer>();
        map.put("aa", 213);
        map.put("bb", 343);

        Map map1 = new HashMap();
        map1.put("cc", 333);
        map1.putAll(map);


        map.remove("cc");

        map.clear();
        System.out.println(map);

        map.get("aa");

        boolean aa = map.containsKey("aa");
        boolean b = map.containsValue(123);
        boolean empty = map.isEmpty();


        Set set = map.keySet();
        Iterator iterator = set.iterator();
        while(iterator.hasNext())
        {
            System.out.println(iterator.next());
        }

        Collection collection = map.values();
        for(Object obj : collection)
        {
            System.out.println(obj);
        }
70、properties

Hashtable子类,该对象是处理配置文件

key和value是string

public static void main(String[] args) throws IOException {
        Properties pros = new Properties();

        FileInputStream fis = new FileInputStream("a.pro");

        pros.load(fis);
        String name = pros.getProperty("name");
        String password = pros.getProperty("password");
    }
71、Collections工具类的使用
public void test(){    List list = new ArrayList();;    list.add(123);    list.add(345);    list.add(-12);    Collections.reverse(list);    System.out.println(list);    Collections.shuffle(list);    System.out.println(list);    Collections.sort(list);    //Collections.max()    int frequency = Collections.frequency(list, 123);    System.out.println(frequency);    List dest = Arrays.asList(new Object[list.size()]);    Collections.copy(dest, list);    List list1 = Collections.synchronizedList(list);}
72、泛型:为什么要用泛型

把元素的类型设计成参数,参数就是泛型

public void test10(){    ArrayList<Integer> list = new ArrayList<Integer>();    list.add(78);    list.add(76);    list.add(89);}
73、自定义泛型结构

泛型类

public class Order<T>{
    String orderName;
    int orderId;
    T orderT;
    
    public Order(){
        //错误,编译不通过
        T[] arr = new T[10];
        //编译通过
        T[] arr = (T[]) new Object[10];
    }
}

public class SubOrder extends Order<String>{
    
}

public class SubOrder2<E> extends Order<E>{
    
}
74、泛型方法
public<T> List<T> copyFromArrayToList(T[] arr){
    ArrayList<T> list = new ArrayList<>();
    
    for(E e: arr)
        list.add(e);
    return list;
}

使用List<?>就不能向里面加父类了

例外

除了添加null之外

75、IO流:File类基本使用
/** * 1、如何创建File类的实例 *  File(String filepath); *  File(String parentpath, String childpath); *  File(File parentFile, String childpath); * * 2、 * 相对路径 * 绝对路径 * * 3、路径分割服 * windows下  \\ * unix:/ */@Test    public void Test() throws IOException {        File file = new File("hello.txt");        //getAbsolutePath();获取绝对路径        System.out.println(file.getAbsolutePath());        //获取路径        System.out.println(file.getPath());        //获取名字        System.out.println(file.getName());        //获取parent        System.out.println(file.getParent());        //获取长度        System.out.println(file.length());        //最近修改时间, long毫秒数        System.out.println(file.lastModified());        //list(),下一层目录内文件的名字        String[] list = file.list();        //listFiles(),直接输出文件        File[] files = file.listFiles();        //重命名,  返回值看看是不是改名成功,并且改变路径        //file 一定要存在        //且file2不能存在        File file2 = new File("hi.txt");        boolean b = file.renameTo(file2);        //判断功能        //判断是否为文件目录        file.isDirectory();        //是否文件        file.isFile();        //是否存在        file.exists();        //是否可读可写        file.canRead();        file.canWrite();        //是否隐藏        file.isHidden();        //创建硬盘中对应的文件或者文件目录        //不走回收站        File file3 = new File("hi.txt");        if(!file3.exists()) {            boolean newFile = file3.createNewFile();        }        File file4 = new File("d:/fda/fdha");        file4.mkdir();        file4.mkdirs();        file4.delete();        //旗下不能有子目录或者子文件    }
76、如何遍历Map的key集, value集, key-value集, 使用上泛型
Map<String, Integer> map = new HashMap<>();Set<String> keySet = map.keySet();for(String key : keySet){    System.out.println(key);}Collection<Integer> values = map.values();Iterator<Integer> iterator = values.iterator();while(iterator.hasNext()){    System.out.println(iterator.next());}Set<Map.Entry<String, Integer>> entry = map.entrySet(); Iterator<Map.Entry<String,Integer>> iterator = enetry.iterator();while(iterator.haxNext()){    Map.Entry<String, Integer> entry = iterator.next();    System.out.println(entry.getKey() + entry.getValue());}
77、IO流原理及流的分类

I = input O = output

处理设备之间的数据传输

数据单位不同:字节流(8bit) 字符流(16bit);

流的角色不同:节点流, 处理流

抽象基类 InputStream OutputStream Reader Writer

节点流(文件流) FileInputStream FileOutputStream FileREader FileWriter

缓冲流 Buffered Buffered Buffered Buffered

 public void test()
    {
        FileReader fr = null;
        try {
            //1、实例化File类的对象,指明要操作的文件
            File file = new File("hello.txt");//相较于当前Module
            //2、提供具体的流
            fr = new FileReader(file);

            //3、数据的读入
            //read():返回读入的字符,如果达到文件末尾,就返回-1;
//        int read = fr.read();
//        while(read != -1)
//        {
//            System.out.println((char)read);
//            read = fr.read();
//        }

            //语法上的修改
            int data;
            while ((data = fr.read()) != -1) {
                System.out.println(data);
            }
        }
        catch (Exception e)
        {
            System.out.println(e);
        }
        finally {
            //流的关闭操作
            try {
                if(fr != null)
                    fr.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        //流的关闭操作
    }
public void etst()
{
    FileReader fr = null;
    FileWriter fw = null;
    try{
        fr = new File("")
    }
}
FileInputStream不能处理txt byte 复制可以

FileReader不能处理图片 char

78、缓冲流BufferedInputStream

为了提高读写效率

public void BufferedStreamTest{	//1、造文件    File srcFile = new File("aa.jpg");    File destFile = new File("aa1.jpg");        //2、造流 节点流    FileInputStream fis = new FileInputStream(srcFile);    FileOutputStream fos = new FileOutputStream(destFile);        //3、造缓冲流    BufferedInputStream bis = new BufferedInputStream(fis);    BufferedOutputStream bos = new BufferedOutputStream(fos);        //4、复制细节    byte[] buffer = new byte[5];    int len;    while((len = bis.read(buffer) != -1))    {        bos.write(buffer, 0, len);    }        //5、关闭资源    //先关外层的,再关内层的    bos.close();    bis.close();    //在关闭外层流的同时,内层流也会自动进行关闭,可以省略    //fos.close();    //fis.close();}
BufferedReader
public void test(){    //创建文件相应的流    BufferedReader br = new BufferedReader(new FileReader(new File("dbcp.txt")));    BufferedWriter bw = new BufferedWriter(new FileWriter(new File("dbcp2.ttxt")));        //读写操作    char[] cbuf = new char[1024];    int len;    while((len = br.read(cbuf)) != -1)    {        bw.write(cbuf, 0, len);    }    //方式二    String data;    while((data = br.readLine()) != null)    {        bw.write(data + "\n");//data中不包含换行符    }        //关闭资源    bw.close();    br.close();}
79、图片的加密
public void test1(){	FileInputStream fis = new FileInputStream(new File("aa.jpg"));    FileOUtputStream fos = new FileOutputStream(new File("aa1.jpg"));        byte[] buffer = new byte[20];    int len;    while((len  = fis.read(buffer)) != -1)    {        for(int i = 0; i< len; i++)        {            buffer[i] = (byte) (buffer[i] ^ 5);        }        fos.write(buffer, 0, len);    }        fos.close();    fis.close();}
80、转换流 InputStreamReader//OutputSteamWriter

转换提供了字节流和字符流之间的转换

解码:字节、字节数组------》字符数组、字符串

编码:字符数组、字符串-----》字节、字节数组

  • 字符集
public void test(){    FileInputStream fis = new FileInputStream("aa.txt");    InputStreamReader isr = new InputStreamReader(fis);//使用系统默认的字符集        char[] cbuf = new char[20];    int len;    while((len = isr.read(cbuf)) != -1)    {        String str = new String(cbuf);        System.out.print(str):    }        isr.close();}
81、常用字符集
  • ASCII:美国标准信息交换码 用一个字节的8位表示
  • ISO8859-1:拉丁码表,欧洲码表, 用一个字节的8位表示
  • GB2312:中国的中文编码表。最多两个字节编码所有字符,看首位是0是1解决是否是两个字节
  • GBK:中国的中文编码的升级,融合了更多的中文文字符号,最多两个字节编码
  • Unicode:国际标准版,融合了目前人类使用的所有字符,为每个字符分派唯一的字符码。都用两个字节存
  • utf-8边长的编码方式,是对Unicode的落地实现
82、标准输入输出流/打印流/数据流
//标准的输入、输出流//System.in:标准输入流,默认从键盘输入//System.out:标准输出流,默认从控制台输出//setIn()  重定向//setOut()   重定向  //练习//从键盘输入字符串,要求将读取到的整行字符串转换成大写输出,然后继续进行输入操作//直到输入e退处程序public void test1(){    //方法一;用Scanner方法,调用next()返回一个字符串    //方法二:使用System.in实现。    InputStreamReader isr = new InputStreamReader(Sysstem.in);        BufferedReader br = new BufferedReader(isr);    while(true)    {        String data = br.readLine();        if(data.equalsIgoreCase("e") || data.eaualsIgnoreCase("exit"))        {            System.out.println("程序结束");            break;        }       	String upperCase = data.toUpperCase();        System.out.println(upperCase):    }        br.close();}
//打印流,只有输出
//PrintStream    PrintWriter
//提供了一系列冲裁的print()  和  println()方法
public void test()
{
    PrintStream ps= null;
    try{
        FileOutputStram fos = new FileOutputStream(new File("aaa.txt"));
        ps = new PrintStream(fos, true);
        if(ps != null){
            System.setOut(ps);
        }
        for(int i = 0; i <= 255; i++)
        {
            System.out.println((char) i );
            if( i % 50 == 0){
                System.out.println();
            }
        }
    }
}
//数据流    操作基本数据类型和String
//DataInputStream    DataOutputStream
//用于读取或写出基本数据类型的数据
public void test3(){
    DataOutputStream dos = new DataOutputStream(new FileOutpetStream("data.txt"));
    dos.writeUTF("姓名");
    dos.writeInt(23);
    dos.writeBoolean(true);
    
    dos.close();
}

//读取要根据写入的顺序
public void read(){
    DataInputStream in = new DataInputStream(new FileInpputStream("data.txt"));
    in.readUTF();
    in.readInt();
    in.readBoolean();
}
83、对象流

ObjectInpuStream ObjectOutputStream

  • 序列化:用ObjectOutputStream类保存基本数据类型或者对象的机制
  • 反序列化:用ObjectInputStream类读取基本类型数据或者对象的机制

不能序列化static和transient修饰成员变量

对象序列化机制允许把内存中的java对象转换成平台无关的二进制流,从而允许把这些二进制流持久地保存在磁盘上,或通过网络将这种二进制流传输到另一个网络节点。当其他程序获取了这种二进制流,就可以恢复成原来的JAVA对象

序列化的好处再余可将任何实现了Serializable接口的对象转化成字节流

对象流的使用 ObjectInpuStream ObjectOutputStream
//序列化过程public void OutputStream(){    ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(new File("aa.dat")));    oos.writeObject(new String("aaa")));    oos.writeObject(new Person("张三", 21));        oos.close;}//反序列化过程public void inpoutStream(){    ObjectInputStream ois = new ObjectInputStream(new FileInputStream("aa.dat"));    Object obj = ois.readObject();        Object obj = ois.readObject();    String str = (String) obj;        ois.close;}//Person需要满足如下要求方可序列化//1、需要实现接口 Serializable   //标识接口//2、需要提供一个序列化版本号serialVersionUID//3、除了当前Person类可序列化要实现Serializable接口之外,还必须保证其内部其他属性也是可序列化的。//4、不能序列化static和transient修饰成员变量@Datapublic class Person implements Serializable{    //序列版本号,自定义异常类都要序列化版本号。    public static final long serialVersionUID = 44444L;        private String name;        private int age;}

如果类没有显示定义这个静态变量,它的值是Java运行时环境根据类的内部细节自动生成的。若类的实例变量做了修改,serialVersionUID会改变,则后续无法还原

84、随机存取文件流 RandomAccessFile

既可以作为输入流,也可以作为输出流。直接继承Object

实现接口 DataInput, DataOutput

重要性差一些

如果RandomAccessFile作为输出流时, 写出到的文件不存在,则创建,

如果写出到的文件存在,则会对原有文件进行覆盖,默认从头覆盖

@Test
public void test1()
{
    //第二个参数可以选择"r"  "rw"  
    //"rwd"  同步文件内容的更新
    //"rws"   同步文件内容和元数据的更新
    RandomAccessFile raf1 = new RandomAccessFile(new File("aa.txt"), "r");
    RandomAccessFile raf2 = new RandomAccessFile(new File("aa.txt"), "rw");
    
    byte[] buffer = new byte[1024];
    int len;
    while((len = raf1.read(buffer)) != -1){
        raf2.write(buffer, 0, len);
    }
    
    raf1.close();
    raf2.close();
}

@Test
public void test2(){
    //对文件内哦让那个的覆盖
    RandomAccessFile raf1 = new RandomAccessFile("hello.txt", "rw");
    //指针移动到3的位置
    raf1.seek(3);
    //raf1.seek(File.length());
    raf1.write("xyz".getBytes());
    
    raf1.close();
}


//使用RandomAccessFile实现数据插入效果
@Test
public void test3(){
    RandomAccessFile raf1 = new RandomAccessFile("hello.txt", "rw");
  
    raf1.seek(3);
    //保存3后面的指针所有数据到StringBuilder中
    StringBuilder builder = new StringBuilder((int) new File("hello.txt").length());
    byte[] buffer = new byte[20];
    
    int len;
    while((len = raf1.read(buffer)) != -1)
    {
        builder.append(new String(buffer, 0, len));
    }
    
    //调回指针,写入"xyz";
    raf1.seek(3);
    raf1.write("xyt".getBytes));
    
    raf1.write(builder.toString().getBytes());
    raf1.close();
}
85、NIO.2 中的Path、Paths、Files类的使用

New IO, Non-Blocking IO

NIO将以更高效的方式i纪念性问及那的读写操作,更加重要了

框架中经常使用

网络编程

网络中实现数据的传输

86、IP地址

127.0.0.1对应着着:Localhost;

public static void main(String[] args){    InetAddress inet1 = InetAddress.getByName("192.168.1.1");    InetAddress inet1 = InetAddress.getByName("www.atguigu.com");	InetAddress.getLocalHost();    InetAddress.getHostName/getHostAddress();}
87、TCP网络编程1

客户端发送一句话给服务端

服务端显示在控制台上

@Test public void client(){    InetAddress inet = InetAddress.getByName("127.0.0.1");    Socket socket = new Socket(inet, 8899);        OutputStream os = socket.getOutputStream();    os.write("你好胖".getBytes());        os.close();    socket.close();} @Testpublic void server(){    ServerSocket ss = new ServerSocket(8899);        Socket socket = ss.accept();        InputStream is = socket.getInputStream();        //存在问题,可能会有乱码    byte[] buffer = new byte[20];    int len;    while((len = is.read(buffer)) != -1)    {        String str = new String(buffer, 0, len);        System.out.println(str);    }        //建议写法    ByteArrayOutputStream baos = new ByteArrayOutputStream();    byte[] buffer = new byte[5];    while((len = is.read(buffer)) != -1)    {        baos.write(buffer, 0, len);    }    System.out.println(baos.toString());    System.out.println(socket.getInetAddress().getHostAddress());        //关闭资源    baos.close();    is.close();    socket.close();    ss.close();}
88、TCP编程例题2

客户端发送文件给服务端

@Test
public void client(){
	Socket socket = new Socket(InetAddress.getByName("127.0.0.1"), 9090);
    
    OutputStream os = socket.getOutputStream();
    FileInputStream fis = new FileInputStream(new File("a.txt"));
    
    byte[] buffer = new byte[1024];
    int len;
    while((len = fis.read(buffer)) != len)
    {
        os.write(buffer, 0, len);
    }
    
    fis.close();
    os.close();
    socket.close();
}

public void server()
{
    ServerSocket ss = new ServerSocket(9090);
    
    Socket socket = ss.accept;
    
    InputStream is = socket.getInputStream();
    
    FileOutputStrem fos = new FileOuptStream(new File("aa.txt"));
    
    byte[] buffer = new byte[1024];
    int len;
    while((len = is.read(buffer)) != -1)
    {
        fos.write(buffer, 0, len);
    }
    
    fos.close();
    is.close();
    socket.close();
    ss.close();
}
89、TCP网络编程3;

返回发送成功给客户端

@Test
public void client(){
	Socket socket = new Socket(InetAddress.getByName("127.0.0.1"), 9090);
    
    OutputStream os = socket.getOutputStream();
    FileInputStream fis = new FileInputStream(new File("a.txt"));
    
    byte[] buffer = new byte[1024];
    int len;
    while((len = fis.read(buffer)) != len)
    {
        os.write(buffer, 0, len);
    }
    socket.shutdownOutput();
    
    //接收服务器端的数据显示到控制台上
    InputStream is = socket.getInputStream();
    ByteArrayOutputStrem baos = new ByteArrayOutputStream();
    
    byte[] buffer = new byte[20];
    int len1;
    while((len1 = is.read(buffer)) != -1)
    {
        baos.write(buffer, 0, len1);
    }
    
    System.out.println(baos.toString());
    
    baos.close();
    fis.close();
    os.close();
    socket.close();
}

public void server()
{
    ServerSocket ss = new ServerSocket(9090);
    
    Socket socket = ss.accept;
    
    InputStream is = socket.getInputStream();
    
    FileOutputStrem fos = new FileOuptStream(new File("aa.txt"));
    
    byte[] buffer = new byte[1024];
    int len;
    while((len = is.read(buffer)) != -1)
    {
        fos.write(buffer, 0, len);
    }
    
    //服务器端给与客户端反馈
    OutputStream os = socket.getOupputStream();
    os.write("你好你好");
    socket.shutdownOutput();
    
    os.close();
    fos.close();
    is.close();
    socket.close();
    ss.close();
}
90、UDP网络编程
public void sender(){    DatagramSocket socket = new DatagramSocket();        String str = "我是UDP方式发送的导弹";    byte[] data = str.getBytes();    InetAddress inet = InetAddress.getLocalHost();    DatagramPacket packet = new DatagramPacket(data, 0, data.length, inet, 9090);            socket.send(packet);    socket.close();}public void receiver(){    DatagramSocket socket = new DatagramSocket(9090);        byte[] buffer = new byte[100];    DatagramPacket packet = new DatagramPacket(buffer, 0, buffer.length);    socket.receive(packet);        System.out.println(new String(packet.getData(), packet.getLength()));        socket.close();}
URL编程

URL统一资源定位符,它标识Internet上某一资源的地址。

它时一种具体的URI,即URL可以用来标识一个资源

五个部分

传输协议、主机名 端口号 资源地址 参数列表

public static void main(String[] args)
{
    URL url = new URL("http://localhost:8080/beauty.jpg");
    
    url.getProtocol();//协议
    url.getHost(); //主机名
    url.getPort();
    url.getPath();
    url.getFile();
    url.getQuery();//获取查询列表
    
    URLConnection urlConnection = url.openConnection();
    
    //访问服务器。
    urlConnection.connect();
    
    InputStream is = urlconnection.getInputStream();
    FileOutputStream fos = new FileOutputStream("a.jpg");
    
    byte[] buffer = new byte[1024];
    int len;
    while((len = is.read(buffer)) != -1)
    {
        fos.write(buffer, 0, len);
    }
    
    is.close;
    fos.close();
    urlConnection.disconnection();
}

反射

反射(Reflection)被视为动态语言的关键,反射机制允许程序在执行期借助于ReflectionAPI取得任何类的内部信息,并能直接操作任意对象的内部内部结构

在运行时判断任意对象所属的类

构造任意一个对象的类

判断任意一个类所具有的成员变量和方法

获取泛型信息

调用任意一个对象的成员变量和方法

处理注解

生成动态代理

java.lang.Class .reflect.Method, .reflect.Field, .reflect.Constructor;

91、反射能干什么
//反射之前public void test(){	Person p1 = new Person("Tom", 12);    p1.age = 10;    System.out.println(p1.toString());        p1.show();    //不能调用私有对象和私有方法}//反射之后public void test01(){    Class clazz = Person.class;    Constructor cons = class.getConstructor(String.class, int.class);        Object obj = cons.newInstance("tom", 12);    Person p = (Person) obj;    System.out.println(obj);        //通过反射,调用对象指定的属性和指定的方法    Field age = clazz.getDeclaredField("age");    age.set(p, 10);    System.out.println(p);        //通过反射机制调用方法    Method show = clazz.getDeclaredMethod("show");    show.invoke(p);        //可以调用私有方法    //私有构造器    Construct cons1 = clazz.getDeclaredConstructor(String.class);    cons1.setAccessible(true);    Person p1 = (Person) cons1.newInstance("Jerry");    System.out.println(p1);        //调用私有属性   	Field name = clazz.getDeclaredField("name");    name.setAccessible(true);    name.set(p, "hanMe");    System.out.println(p);        //调用私有方法    Method showMethod = clazz.getDeclaredMethod("showNation", String.class);    showMethod.setAccessible(true);    String nation = (String) showNametion.invoke(p1, "中国");}
疑问:如何保证封装性?如何看待这两个技术

不矛盾。封装性建议我们调用public方法,反射可以让我们调用private,但是建议用public方法

疑问:通过直接new的方式或者反射方式都可以调用公共的结构,用哪个

建议用new的模式

什么时候会使用反射?

反射特征,动态性

92、关于java.lang,Class的理解

1、类加载过程:

程序经过javac.exe命令后,会生成一个或者多个字节码文件(.class结尾)

java.exe命令对某个字节码文件进行解释运行。相当于将某个字节码文件加载到内存中,这个过程就教类的加载,加载到内存中的类就叫运行时类,就作为Class类的实例

2、换句话说,Class的实例就对应着一个运行时类。

93、获取Class实例方式
public void test(){    //方式1  .class()    Class clazz1 = Person.class;    System.out.println(clazz1);        //方式2:通过运行时类的对象 .getClass();    Person p1 = new Person();    Class clazz2 = p1.getClass();        //方式3:调用Class的静态方法    Class clazz3 = Class.forName("com.zhou.Person");	    //都是同一个运行时类    System.out.println(clazz1 == clazz2); //true;    System.out.println(clazz1 == clazz3); //true;        //前三个需要掌握            //方式4:使用类的加载器  ClassLoader();    ClassLoader classLoader = ReflectionTest.class.getClassLoader();    Class clazz4 = classLoader.loadClass("com.zhou.Person");    System.out.println(clazz1 == clazz4);}

只要数组的元素类型与维度一样,就是同一个class;

94、了解类加载器

对于自定义类,使用系统类加载器进行加载

使用系统类getParent()方法,获取扩展类加载器

调用扩展类getPreant()方法, 无法获取引导类加载器;

引导类加载器主要负责加载java核心类库

public void test1(){    ClassLoader classLoader = ClassLoaderTest.class.getClassLoader();    System.out.println(classLoader); //系统加载器        ClassLoader classLoader1 = classLoader.getParent(); //扩展类加载器            ClassLoader classLoader2 = classLoader1.getParent();//获取不到引导类加载器}
95、使用classLoader加载配置文件

尽量放在src下

public void test2(){    //之前的方法,方式一    Properties pros = new Properties();    //此时的文件默认在当前的module下    FileInputStream fis = new FileInputStream("jdbc.properties");    pros.load(fis);        String user = pros.getProperty("user");    String password = pros.getProperty("password");        System.out.println(user + password);}//方式二public void test3(){    Properties pros = new Properties();    ClassLoader classLoader = ClassLoaderTest.class.getClassLoader();        //默认相对路径在当前module的src下    InputStream fis =  fisclassLoader.getResourceAsStream("jdbc.properties");        pros.load(fis);        String user = pros.getProperty("user");    String password = pros.getProperty("password");        System.out.println(user + password);}
96、创建运行时类的对象

通过反射方式,创建对应的运行时类的对象

public void test1(){    Class clazz = Person.class;        //newInsatnce():    //调用此方法,创建对应的运行时类的对象    //1、运行时类必须提供空参构造器    //2、空参构造器的访问权限得够,通常设置为public.    Person p = (Person) clazz.newInstance();}
public Object getInstance(String classpath){	return Class.forName(classpath).newInstance;}
97、获取运行时类的属性结构及其内部结构
public void test()
{
    Class clazz = Person.class;
    
    //获取属性结构
    //getFields():获取当前运行时类及其父类中声明为public的属性
    Field[] fields = clazz.getFields();
    System.out.println(fields);
    //getDeclaredFields():
    //获取当前当前运行时类中声明的所有属性,不包含父类中声明的属性
    Filed[] fieldss = clazz.getDeclaredFields();
    System.out.println(fieldss);
}

//属性的内容
//权限修饰符  数据类型   变量名
public void test2()
{
   	Class clazz = Person.class;
    Filed[] fieldss = clazz.getDeclaredFields();
    for(Field f : fieldss)
    {
        //1、权限修饰符
        int modifier = f.getModifiers();
        System.out.println(Modifier.toString(modifier));
  
        //2、数据类型
        Class type = f.getType();
        System.out.println(type.getname);
       	
        //3、变量名
        String fName = f.getName();
        System.out.println(fName);
    }
}
98、方法的结构
public void test()
{ 
    Class clazz = Person.class;
    
    //所有父类中声明为public的方法
    Method[] methods = clazz.getMethods();
    
    //Person类中所有的方法,不包含父类中声明的
   	Method[] methodss = clazz.getDeclaredMethods();
}

//权限修饰符   返回值类型   方法名(参数类型1) throws;

public void test2()
{
    //获取方法声明的注解
    Class clazz = Person.class;
    Method[] methodss = clazz.getDeclaredMethods();
    for(Method f : methodss)
    {
        //获取方法的注解
        Annotation[] annos = m.getAnnotations();
        for(Annotation a : annos)
        {
            System.out.println(a);
        }

        //权限修饰符
        System.out.println(Modifier.toString(m.getModifer));
        
        //返回值类型
        m.getReturnType().getName();
        
        //方法名
      	m.getName();
        
        
        //形参列表
        m.getParameterTypes();
        
        //抛出异常
        m.getExceptionTypes();
    }
}
99、构造器
public void test()
{
    Class clazz = Person.class;
    
    //获取属性结构
    //getFields():获取当前运行时类及其父类中声明为public的属性
    Constructor[] fields = clazz.getConstructors();
    System.out.println(fields);
    //getDeclaredFields():
    //获取当前当前运行时类中声明的所有属性,不包含父类中声明的属性
    Constructor[] fieldss = clazz.getDeclaredConstructors();
    System.out.println(fieldss);
}
100、运行时类的父类
public void test2()
{
    Class clazz = Person.class;
    
    //获取运行时的父类
    Class superclass = clazz.getSuperclass();
    System.out.println(superclass);
    
    //获取带泛型的父类
    Type superclassa = clazz.getGenericSuperclass();
    System.out.println(superclassa);
    
    //带泛型的父类的泛型
    ParameterizedType paramType = (ParameterizedType) superclasa;
    Type[] actualTypeArguments = paramType.getActualTypeArguments();
    System.out.println(actualTypeArguments);
    
    //getTypeName;
    //(class) actualTypeArguments[0].getName();
    
    
}
101、获取运行时类实现的接口
public void test(){
	Class clazz = Person.class;
    
    Class[] interfaces = clazz.getInterfaces();
}
102、获取运行时类所用的包/注解
public void test(){
	Class clazz = Person.class;
    
   	Package pack = clazz.getPackage();
    
    clazz.getAnnotations();
}
103、调用运行时类中指定的结构
public class R{
	public void testField()
    {
        Class clazz = Person.class;
        //创建运行时类对象
        Person p = (Person) clazz.newInstance();
        
        //获取指定的属性
        Field id = clazz.getField("id");
        
        //设置当前属性值
        id.set(p, 12);
         
        int pId = (int) id.get(p);
    }
}

//调用方法
public void test()
{
    Class clazz  = Person.class;
    
    //创建运行时类对象
    Person p = (Person) clazz.newInstance();
    
    //1、获取指定方法
    Method show = clazz.getDeclaredMethod("show", String.class);
    
    show.setAccessible(true);
    
    //参数一:方法的调用者,参数二:给方法形参赋值的实参
    show.invoke(p, "chn");
}


//调用构造器 
public void test()
{
    Class clazz = Person.class;
    
    //获得指定的构造器
    Constructor constructor = clazz.getDeclaredConstructor(String.class);
    constructor.setAccessible(true);
    
    //调用此构造器创建运行时类的对象
    Person per = (Person) constructor.newInstance("tom");
}
104、反射的应用:动态代理
//动态代理举例
interface Human{
    String getBelief();
    
    void eat(String food);
}

//被代理类
class SuperMan implements Human{
    public String getBelief(){
        return "I believe I can fly!";
    }
    
    public void eat(String food)
    {
        System.out.println("我喜欢吃" + food);
    }
}

//要想实现动态代理,需要解决的问题?
//问题一:如何根据加载到内存中的被代理类,动态的创建一个代理类及其对象
//问题二:当桶过代理类的对象调用方法时,如何东岱的去调用被代理类中的同名方法?

class ProxyFactory{
    //调用此方法,返回一个代理类的对象,解决问题一
    public static Object getProxyInstance(Object obj){
        MyInvocationHandler handler = new MuInvocationHandler();
        handler.bind(obj);
        //参数一:代理类的加载器
        //参数二:代理类的实现接口
        //参数三:
        return Proxy.newProxyInstance(obj.getClass().getClassLoader, obj.getClass().getInterfaces(), handler)
    }
}

class MyInvocationHandler implements InvocationHandler{
    private Object obj;//赋值时, 也需要使用被代理类的对象进行赋值
    
    //当我们哦通过代理类的对象,调用方法a时,就会自动调用如下方法
    //将被代理类要执行的方法a的功能就声明在invoke()中
    public void bind(Object obj)
    {
        this.obj = obj;
    }
    @Override
   	public Object invoke(Object proxy, Method method, Object[] args)
    {
        //代理类对象调用的方法,此方法即作为了被代理对象调用的方法。
        //obj:被代理类的对象
        Object returnValue = method.invoke(obj, args);
        
        //上述方法的返回值就作为invoke方法的返回值。
        return returnValue;
    }
}
public class ProxyTest{
	public static void main(Stirng[] args)
    {
        SuperMan superMan = new SuperMan();
        
        //proxyInstance:代理类的对象
        Human h = (Human) ProxyFacktory.getProxyInstance(superMan);
        
        h.getBelief();
        h.eat("四川麻辣烫");
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值