15-1 面试核心部分要点(基础部分给新手看的,祝莘莘学子早日学业有成) --不要害怕Java难,这两章掌握了,Java基础就掌握了

  • 时间:
  • 来源:互联网
  • 文章标签:

Dubbo框架应用总结

1 提供者,消费者及第三方接口pom文件都要加载dubbo的依赖 --父级工程直接都继承自父级即可(父级pom文件中加载dubbo依赖)
2 定义第三方的dubbo接口 编写Dubboservice接口
3 定义服务提供者服务器yml文件中配置dubbo(只配置dubbo包扫描,定义应用名称,指定连接注册中心,指定传输协议及dubbo传输服务的端口) service层serviceImpl实现类上添加**@Service**(这是dubbo框架的注解)并实现dubbo框架里的第三方接口即可
4 定义服务消费者服务器yml文件中配置dubbo(只需要配置dubbo包扫描,定义应用名称,指定连接注册中心)即可 controller层添加**@Reference()注解**–这是dubbo框架提供的注解DI依赖注入第三方接口类型对象即可 直接去调用提供者的服务器了!!

Java基础

Java语言平台版本: JEE(企业版)
Java语言跨平台:不同平台上安装一个Java虚拟机(JVM)即可
JDK是 Java 语言的软件开发工具包。JDK是整个java开发的核心包括了Java运行环境JRE、Java工具和Java基础类库 --而JRE中包含JVM和Java核心类库

标识符:就是名字(包名,类名,变量名等),可以由字母、数字、下划线(_)、美元符($)组成,不能以数字开头。
包名:公司域名倒着写(一般都小写),类首字母大写驼峰命名法
运行与工作原理 --先编译再由JVM运行
在这里插入图片描述
数据类型
八种基本类型及引用类型(就是对象类型)–它的值是指向内存空间的引用,就是地址,所指向的内存中保存着的变量所表示的一个值或一组值。
在这里插入图片描述
重点经典语句

//Scanner scan=new Scanner(System.in);
//String msg=scan.nextLine();
String msg= new Scanner(System.in).nextLine();
double r=new Scanner(System.in).nextDouble();  //圆半径double类型
int a=new Scanner(System.in).nextInt();

平年闰年:能被4整除,并且不能被100整除或者能被400整除

if((y%4==0&&y%100!=0)||y%400==0){ r="闰年";}

求三个数的最大值

int max = a>b?(a>c?a:c):(b>c?b:c);

打印8,88,888,8888

package day999;
public class ttttt {
       public static void main(String[] args) {
           f();
       }
       public static void f(){  for(int i=8;i<=10000;i=i*10+8){System.out.println(i);}   }
}

打印99乘法表

 for (int i = 1; i < 9; i++) {
     for (int j = 1; j <= i; j++) {
         System.out.print(i+"*"+j+"="+i*j+" ");   }
              System.out.println();
 }

嵌套for循环 --外循环执行1次,内循环执行多次. 外循环控制行,内循环控制列
在这里插入图片描述
用来终止循环两种方式:break中断当前循环,continue跳出本次循环进入下一轮

数组

数组Array是用于储存多个相同类型数据的集合 --通过下标获取元素
创建数组:动态初始化和静态初始化
int[] a = new int[5];
int[] a ={1,2,3,4,5,6,7,8}; --静态初始化
int[] a =new int[]{1,2,3,4,5};

Ø length属性获取数组长度 --String类型长度是length()方法,collection集合大小是size()方法
Ø 数组一旦创建,长度不可变
Ø 允许0长度的数组

数组API

a.length //获取数组长度
Arrays.toString(a); //数组转为String
Arrays.sort(a); //对数组排序
Arrays.copyOf(a,6); //数组复制成一个指定长度的新数组

数组冒泡排序

private static int[] sortm(int[] a){
//外循环控制行,内循环控制列.外循环执行一次,内循环执行多次
for(int i=0; i<a.length-1; i++){
for(int j=0; j<a.length-1; j++){
if(a[j]>a[j+1]){
int t=a[j];
a[j] = a[j+i];
a[j+1]=t;
}
}
}
return a;
}

面向对象

三大特征:封装性,继承,多态

Java语言最基本单位就是类,类似于类型
类是一类事物的抽象

java把内存分成5大区域,重点关注栈和堆。

Person p = new Person();
1、 一般来讲局部变量存在栈中,方法执行完毕内存就被释放
2、 对象(new出来的东西)存在堆中,对象不再被使用时,内存才会被释放 --只要有new,就会新开辟空间在堆内存中存入对象
3、 每个堆内存的元素都有地址值存放在栈中(就是引用类型的变量p持有对象的地址值)
4、 对象中的属性都是有默认值的

private关键字–是一个权限修饰符,用于修饰成员变量和成员函数,被私有化的成员只能在本类中访问。
想要修改只能,对外提供公共的,get和set方法。

构造方法是一种特殊的方法,它是一个与类同名且返回值类型为同名类类型的方法。对象的创建就是通过构造方法来完成,其功能主要是完成对象的创建或者对象的初始化(参数赋值)。当类实例化一个对象时会自动调用构造方法。
构造代码块
1、 在类的内部,方法外部,的代码块。
2、 通常用于抽取构造方法中的共性代码。
3、 每次调用构造方法前都会调用构造代码块
4、 优先于构造方法加载
局部代码块–方法里面的代码块

1、 静态代码块:在类加载时就加载,并且只被加载一次,一般用于项目的初始化
2、 构造代码块:在调用构造方法前会自动调用,每次创建对象都会被调用
3、 局部代码块:方法里的代码块,方法被调用时才会执行
4、 静态代码块:static{ },位置:在类里方法外
多态
父类引用指向子类对象,
多态中,编译看左边,运行看右边

接口

通过interface关键字创建接口 --抽象类用abstract关键字描述
接口通过implements让子类来实现 --子类和抽象类之间是extends关系
接口是对外暴露的规则,是一套开发规范
接口提高了程序的功能扩展,降低了耦合性
接口里是没有构造方法的
在创建实现类的对象时默认的super(),是调用的默认Object的无参构造
接口里没有成员变量,都是常量–默认补齐final static

单例设计模式

1、 私有化构造方法 --不让外界直接new
2、 在类的内部创建好对象 --static :静态只能调用静态
3、 对外界提供一个公共的get(),返回一个已经准备好的对象–static是为了外界不通过对象访问而是通过类名直接方法
饿汉式 --先创建了对象
class Single{
private Single() {}
static private Single s = new Single();
static public Single get(){
return s;
}
}
懒汉式 --调用时才创建对象(延迟加载思想)
class Single{
private Single() {}
static private Single s = null;
synchronized static public Single get(){ //使用同步锁锁住方法
if(s==null){
s = new Single();
}
return s;
}
}

API

Object --所有对象的顶级父类

boolean equals(Object obj) --某个对象是否与此对象“相等”。默认是比较内存地址值,比较对象的属性,可以重写该方法
protected void finalize() --当垃圾回收器确定不存在对该对象的更多引用时,由对象的垃圾回收器调用此方法。
int hashCode() --返回该对象的哈希码值。
String toString() --默认返回对象的字符串表示的地址值,重写了toString()打印的是属性的值

String --字符串对象,是一个封装char[]数组的对象,字符串不可变

创建String对象
1 String str=“abc”; //第一次使用字符串,java会在字符串常量池创建一个对象。再次使用相同的内容时,会直接访问常量池中存在的对象。
2 new String(char[]) //new就会在堆中开辟新的内存

length()
charAt(3) //返回指定索引处的 char 值
lastIndexOf()
substring(3,7) //截取时含头不含尾[3,7)
equals() //判断两个字符串的内容是否相同
startsWith()
endsWith(“jk”) //是否以指定后缀结束
split() //切割字符串
trim() //去除字符串两端的空格
String.valueOf(10) //把指定的参数转换成String类型

String类做字符串拼接的过程效率极其低下 --字符串不可变,每次加会创建新对象
StringBuilder/StringBuffer
是可变的字符序列
提供了一组可以对字符内容修改的方法
常用**append()**来代替字符串做字符串连接
内部字符数组默认初始容量是16,如果大于16会尝试将扩容

StringBuilder sb=new StringBuilder();
sb.append(s);

Number --数字包装类的抽象父类

在这里插入图片描述
Integer
创建对象
new Integer(5);新建对象
Integer.valueOf(5);
parseInt();字符串转换成int
toBinaryString();把整数转换成2进制数据
toOctalString();把整数转换成8进制数据
toHexString();把整数转换成16进制数据
Double
new Double(3.14)
Double.valueOf(3.14)//和 new 没有区别
Double.parseDouble();

BigDecimal/BigInteger

BigDecimal:常用来解决精确的浮点数运算。
BigInteger:常用来解决超大的整数运算。
创建对象
BigDecimal.valueOf(2);
常用方法
add(BigDecimal bd): 做加法运算
substract(BigDecimal bd) : 做减法运算
multiply(BigDecimal bd) : 做乘法运算
divide(BigDecimal bd) : 做除法运算
divide(BigDecimal bd,保留位数,舍入方式):除不尽时使用
setScale(保留位数,舍入方式):同上
pow(int n):求数据的几次幂

日期类Date

创建对象
new Date():封装的是系统当前时间的毫秒值 --从1970-1-1 0点开始的毫秒值
new Date(900000000000L):封装指定的时间点
常用方法
getTime():取内部毫秒值
setTime():存取内部毫秒值
getMonth():获取当前月份
getHours():获取当前小时
compareTo(Date):当前对象与参数对象比较。当前对象大返回正数,小返回负数,相同0。

日期工具SimpleDateFormat

创建对象
new SimpleDateFormat(格式)
格式:yyyy-MM-dd HH:mm:ss
MM/dd/yyyy
常见方法
format(Date):把Date格式化成字符串
parse(String):把String解析成Date

IO读写数据流 --分为字节流和字符流

java.io包:
File
字节流:针对二进制文件
InputStream
–FileInputStream
–BufferedInputStream
–ObjectInputStream
OutputStream
–FileOutputStream
–BufferedOutputStream
–ObjectOutputStream
字符流:针对文本文件。读写容易发生乱码现象,在读写时最好指定编码集为utf-8
Reader
–BufferedReader
–InputStreamReader
–PrintWriter/PrintStream
Writer
–BufferedWriter
–OutputStreamWriter

File文件流

创建对象
File f = new File(String pathname); //文件或文件夹
length():文件的字节量
exists():是否存在,存在返回true
isFile():是否为文件,是文件返回true
isDirectory():是否为文件夹,是文件夹返回true
getName():获取文件/文件夹名
getParent():获取父文件夹的路径
getAbsolutePath():获取文件的完整路径
createNewFile():新建文件,文件夹不存在会异常,文件已经存在返回false
mkdirs():新建多层不存在的文件夹\a\b\c
mkdir():新建单层不存在的文件夹\a
delete():删除文件,删除空文件夹
list():返回String[],包含文件名
listFiles():返回File[],包含文件对象

 File f = new File("D:\\teach\\a");
 File[] files = f.listFiles();

递归求目录总大小

求目录的总大小:
1、把指定目录封装成File对象
2、把文件夹列表列出来
3、判断,如果是文件,直接把f.length()相加
4、判断,如果是文件夹,继续列表,继续判断,如果是文件相加,如果又是文件夹,继续列表,继续判断,如果是文件相加......
5、如果是文件夹,递归调用方法本身的业务逻辑
package cn.tedu.io;
public class Test2_File2 {
   public static void main(String[] args) {
       File file = new File("D:\\teach\\a");
	   int size =count(file);
       System.out.println(size);
}
   private static int count(File file) {
       File[] files = file.listFiles();
       int sum = 0;//记录文件的大小
       for (int i = 0; i < files.length; i++) {  //length数组长度大小
          if(files[i].isFile()) {
              sum += files[i].length();         //length()文件字节量大小
          }else if(files[i].isDirectory()){
              sum += count(file[i]);//把当前遍历到的文件夹继续循环判断求和
          }
    }
       return sum ;
  }
}

InputStream抽象类

abstract int read() --从输入流中读取数据的下一个字节。
int read(byte[] b) --从输入流中读取一定数量的字节,并将其存储在缓冲区数组 b 中。
int read(byte[] b, int off, int len) --将输入流中最多 len 个数据字节读入 byte 数组。
void close() --关闭此输入流并释放与该流关联的所有系统资源。

FileInputStream子类

创建对象
FileInputStream(File file) --通过打开一个到实际文件的连接来创建一个 FileInputStream,该文件通过文件系统中的 File 对象 file 指定。
FileInputStream(String pathname) --通过打开一个到实际文件的连接来创建一个 FileInputStream,该文件通过文件系统中的路径名 name 指定。

BufferedInputStream子类

缓冲输入以及支持 mark 和 reset 方法的能力。在创建 BufferedInputStream 时,会创建一个内部缓冲区数组(默认8M大小)
创建对象
BufferedInputStream(InputStream in) --创建一个 BufferedInputStream 并保存其参数,即输入流 in,以便将来使用。

字符流读取Reader抽象类

int read() 读取单个字符。
int read(char[] cbuf) 将字符读入数组。
abstract int read(char[] cbuf, int off, int len)将字符读入数组的某一部分。
int read(CharBuffer target) 试图将字符读入指定的字符缓冲区。
abstract void close() 关闭该流并释放与之关联的所有资源。

InputStreamReader子类

InputStreamReader 是***字节流通向字符流***的桥梁:它使用指定的 charset 读取字节并将其解码为字符。
创建对象
InputStreamReader(InputStream in, String charsetName) 创建使用指定字符集的 InputStreamReader。
InputStreamReader(InputStream in) 创建一个使用默认字符集的 InputStreamReader。

FileReader子类

创建对象
FileReader(String fileName) 在给定从中读取数据的文件名的情况下创建一个新 FileReader。
FileReader(File file) 在给定从中读取数据的 File 的情况下创建一个新 FileReader。

BufferedReader子类 --读一行写一行(配合PrintWriter )

创建对象
BufferedReader(Reader in) 创建一个使用默认大小输入缓冲区的缓冲字符输入流。
readLine(); 读一行
println(line); 写一行line是读取的那一行
文件的读取

private static void method1() throws Exception {
      // long s = System.currentTimeMillis();
       InputStream in = new FileInputStream("D:\\teach\\1.jpg");
       int b = 0;
       while ((b = in.read()) != -1) {
            System.out.println(b);
       }
     //  s = System.currentTimeMillis() - s;
     //  System.out.println(s + "--");// 7515
    //   long ss = System.currentTimeMillis();
       InputStream in2 = new BufferedInputStream(new FileInputStream("D:\\teach\\1.jpg"));
       int b2 = 0;
       while ((b2 = in2.read()) != -1) {
            System.out.println(b2);
       }
     //  ss = System.currentTimeMillis() - ss;
    //   System.out.println(ss + "==");// 32    
       in.close();
       in2.close();
    }
字符流读写乱码

new BufferedReader(new InputStreamReader(?,”utf-8”));
new BufferedWriter(new OutputStreamWriter(?,”utf-8”));
//默认是系统的编码,GBK写出。
//如果打开和写出的编码用的表不一致,会造成乱码。
了解 JDK1.7新特性之IO关流

private static void customBufferStreamCopy(File source, File target) {
    InputStream fis = null;
    OutputStream fos = null;
    try {
        fis = new FileInputStream(source);
        fos = new FileOutputStream(target);
        byte[] buf = new byte[8192];
        int i;
        while ((i = fis.read(buf)) != -1) {
            fos.write(buf, 0, i);
        }
    }
    catch (Exception e) {
        e.printStackTrace();
    } finally {    //新特性貌似就是关闭时再判断是否IO流为空,流里为空就不关?占位用的?
        close(fis);
        close(fos);
    }
}
private static void close(Closeable closable) {
    if (closable != null) {
        try {
            closable.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
上述代码对于异常处理十分复杂,
对于资源的关闭也很麻烦,那么可以和下面的进行对比:
private static void customBufferStreamCopy(File source, File target) {
    try (InputStream fis = new FileInputStream(source);
        OutputStream fos = new FileOutputStream(target)){
        byte[] buf = new byte[8192]; 
        int i;
        while ((i = fis.read(buf)) != -1) {
            fos.write(buf, 0, i);
        }
    }
    catch (Exception e) {
        e.printStackTrace();
    }
}

OutputStream抽象类

void close() 关闭此输出流并释放与此流有关的所有系统资源。
void flush() 刷新此输出流并强制写出所有缓冲的输出字节。
void write(byte[] b) 将 b.length 个字节从指定的 byte 数组写入此输出流。
void write(byte[] b, int off, int len) 将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此输出流。
abstract void write(int b) 将指定的字节写入此输出流

FileOutputStream子类

创建对象
FileOutputStream(String name) 创建一个向具有指定名称的文件中写入数据的输出文件流。FileOutputStream(File file) 创建一个向指定 File 对象表示的文件中写入数据的文件输出流。
FileOutputStream(File file, boolean append) –追加创建一个向指定 File 对象表示的文件中写入数据的文件输出流。

BufferedOutputStream子类

创建对象
BufferedOutputStream(OutputStream out) 创建一个新的缓冲输出流,以将数据写入指定的底层输出流。

Writer抽象类 字符流写出

常用方法
void write(char[] cbuf) 写入字符数组。
abstract void write(char[] cbuf, int off, int len) 写入字符数组的某一部分。
void write(int c) 写入单个字符。
void write(String str) 写入字符串。
void write(String str, int off, int len) 写入字符串的某一部分。
abstract void close() 关闭此流,但要先刷新它。

OutputStreamWriter子类

OutputStreamWriter 是***字符流通向字节流***的桥梁
创建对象
OutputStreamWriter(OutputStream out, String charsetName) 创建使用指定字符集的OutputStreamWriter。
OutputStreamWriter(OutputStream out) 创建使用默认字符编码的 OutputStreamWriter。

FileWriter子类

创建对象
FileWriter(String fileName) 根据给定的文件名构造一个 FileWriter 对象。
FileWriter(String fileName, boolean append) 根据给定的文件名以及指示是否附加写入数据的 boolean 值来构造 FileWriter 对象。

BufferedWriter子类

BufferedWriter(Writer out) 创建一个使用默认大小输出缓冲区的缓冲字符输出流。

示例 --文件复制 批量读写
package cn.tedu.io;
//文件复制
public class Test4_Copy {
       public static void main(String[] args) throws Exception {
              // 1,创建读取文件和写出文件
              File from = new File("D:\\teach\\a\\1.txt");
              File to = new File("D:\\teach\\a\\to.txt");
//调用copy完成文件复制
              copy(from, to);
       }
       //封装了文件复制的工具,将来可以通过类名.直接调用
       public static void copy(File from, File to) throws Exception {
              // 2,读取from,写出到to
              InputStream in = new FileInputStream(from);
              OutputStream out = new FileOutputStream(to);
              // 3,开始读,读到-1为止
              int b = 0;// 记录每次读取到的数据
              while ((b = in.read()) != -1) {
                     out.write(b);// 把读到的内容写出去
              }
              // 4,关闭资源
              in.close();
              out.close();
       }
}
package cn.tedu.io;
//文件复制
public class Test4_Copy {
       public static void main(String[] args) throws Exception {
              // 1,创建读取文件和写出文件
              File from = new File("D:\\teach\\a\\1.txt");
              File to = new File("D:\\teach\\a\\to.txt");
              copyByte(from, to);// 一个字节一个自己的复制
              copyArray(from, to);// 一个数组一个数组的复制
       }
       // 一个数组一个数组的复制
       private static void copyArray(File from, File to) throws Exception {
              // 2,读取from,写出到to
              InputStream in = new FileInputStream(from);
              OutputStream out = new FileOutputStream(to);
              // 3,批量的读和写
              int b = 0;// 记录每次读取到的数据
              //源码:数组默认的长度一般是8M数组的长度就是8*1024
              byte[] bs = new byte[8*1024];//用来缓存数据
              while ((b = in.read(bs)) != -1) {//读取数组中的内容
                    out.write(bs);// 把读到的数组里的内容写出去
              }
          // 4,关闭资源
              in.close();
              out.close();
      }
       // 封装了文件复制的工具,将来可以通过类名.直接调用
      public static void copyByte(File from, File to) throws Exception {
              // 2,读取from,写出到to
              InputStream in = new FileInputStream(from);
              OutputStream out = new FileOutputStream(to);
              // 3,开始读,读到-1为止
              int b = 0;// 记录每次读取到的数据
              while ((b = in.read()) != -1) {
                     out.write(b);// 把读到的内容写出去
              }
              // 4,关闭资源
              in.close();
              out.close();
       }
}

序列化 / 反序列化

序列化:利用ObjectOutputStream,对象的信息,按固定格式转成一串字节值输出并持久保存到磁盘化。
反序列化:利用ObjectInputStream,读取磁盘中序列化数据,重新恢复对象。
1、 需要序列化的文件必须实现Serializable接口以启用其序列化功能。–implements
2、 不需要序列化的数据可以被修饰为static的,由于static属于类,不随对象被序列化输出。
3、 不需要序列化的数据也可以被修饰为transient临时的,只在程序运行期间,在内存中存在不会被序列化持久保存。
4、 在反序列化时,如果和序列化的版本号不一致时,无法完成反序列化。

ObjectOutputStream/ObjectInputStream

ObjectOutputStream(OutputStream out) 创建写入指定 OutputStream 的 ObjectOutputStream。
void writeObject(Object obj) 将指定的对象写入 ObjectOutputStream。
ObjectInputStream(InputStream in) 创建从指定 InputStream 读取的 ObjectInputStream。
Object readObject() 从 ObjectInputStream 读取对象,读取序列化数据。

package cn.tedu.serializable;
public class Test5_Seri {
   public static void main(String[] args) throws Exception, IOException {
      //序列化:就是把java对象保存在磁盘中
      ObjectOutputStream os = new ObjectOutputStream(new FileOutputStream("D:\\teach\\a\\student.txt"));
      Student s = new Student("张三",20,"成都");
      os.writeObject(s);
      os.close();//关闭输出资源
      //反序列化:从磁盘读到程序里
      ObjectInputStream in = new ObjectInputStream(new FileInputStream("D:\\teach\\a\\student.txt"));
      //读到的对象,默认是Object,需要强转成子类
      Student s2 = (Student)in.readObject();
      System.out.println(s2);
   }
}

BIO、NIO、AIO的区别

BIO:阻塞IO,BIO 就是传统的 java.io 包 --交互的方式是同步、阻塞方式
NIO:非阻塞IO,NIO 是 Java 1.4 引入的 java.nio 包 --构建多路复用的、同步非阻塞 IO 程序
AIO:异步IO,AIO 是 Java 1.7 之后引入的包,是 NIO 的升级版本,是应用操作之后会直接返回,不会堵塞在那里,当后台处理完成,操作系统会通知相应的线程进行后续的操作

数组和链表区别

List是一个接口,它有两个常用的子类,ArrayList和LinkedList,看名字就可以看得出一种是基于数组实现另一个是基于链表实现的
数组ArrayList遍历快,因为存储空间连续,插入或修改元素慢链表LinkedList遍历慢,因为存储空间不连续,插入或修改数据快,要去通过指针定位下一个元素,所以链表遍历慢。

泛型+集合( 通过泛型的语法定义,约束集合元素的类型,进行安全检查,把错误显示在编译期)

泛型可以在接口、方法、返回值上使用 --泛型的数据类型只能是引用类型,不能是基本类型
public interface Collection { }
public void print(E e) { }在方法返回值前声明了一个表示后面出现的E是泛型,而不是普通的java变量。

集合

Collection接口

List接口 : 数据有序,可以重复,元素都有索引
Set接口 : 数据无序,不可以存重复值
在这里插入图片描述
常用方法
boolean add(E e):添加元素。
boolean addAll(Collection c):把小集合添加到大集合中 。
boolean contains(Object o) : 如果此 collection 包含指定的元素,则返回 true。
boolean isEmpty() :如果此 collection 没有元素,则返回 true。
Iterator iterator():返回在此 collection 的元素上进行迭代的迭代器。
boolean remove(Object o) :从此 collection 中移除指定元素的单个实例。
int size() :返回此 collection 中的元素数。
Objec[] toArray():返回对象数组

List接口

常用方法
ListIterator listIterator() 返回此列表元素的列表迭代器(按适当顺序)。
ListIterator listIterator(int index) 返回列表中元素的列表迭代器(按适当顺序),从列表的指定位置开始。
void add(int index, E element) 在列表的指定位置插入指定元素(可选操作)。
boolean addAll(int index, Collection<? extends E> c) 将指定 collection 中的所有元素都插入到列表中的指定位置(可选操作)。
List subList(int fromIndex, int toIndex) 返回列表中指定的 fromIndex(包括 )和 toIndex(不包括)之间的部分视图。
E get(int index) 返回列表中指定位置的元素。
int indexOf(Object o) 返回此列表中第一次出现的指定元素的索引;如果此列表不包含该元素,则返回 -1。

ArrayList 内部数组默认初始容量是10 --查询快,插入或修改元素慢

LinkedList 双向链表,两端效率高。底层就是数组和链表实现的。–查询慢,插入或修改元素快

常用方法
add()
get()
size()
remove(i)
remove(数据)
iterator()
addFirst() addLast()
getFirst() getLast()
removeFirst() removeLast()

Set接口 --常用于给数据去重

Ø HashSet:底层是哈希表,包装了HashMap,相当于向HashSet中存入数据时,会把数据作为K,存入内部的HashMap中。当然K仍然不许重复。
Ø TreeSet:底层就是TreeMap,也是红黑树的形式,便于查找数据。
Ø HashMap实现中,当哈希值相同的对象,会在同一个hash值的位置存储不同属性的数据。

HashCode()和equals()方法对比

HashCode()查询快,比较的是hash值是否一致(可以将hash值想象成物理空间地址值)
equals()查询比较与Hashcode()相比慢,比较的是元素内容是否相同
所以通常这两个配合使用先HashCode()快速查询出hash值一致的元素位置里(可以想象成该位置是一个大箱子这里存放了hash值一样的元素)的所有内容,再用equals()挨个比较该箱子里的这部分元素内容是否与要比较的元素相同即可!!!若不用HashCode()直接用equals()查询内容很多时,会很慢!!!HashCode()相当于先定位个位置!!只比较在该位置上的元素即可!!

Map接口 --初始容量是16,默认的加载因子是0.75 --collection集合添加是add(),map添加是put()

类型参数: K - 此映射所维护的键的类型V - 映射值的类型。
也叫哈希表、散列表。常用于存键值对结构的数据。其中的键不能重复,值可以重复.
在这里插入图片描述
常用方法
void clear() 从此映射中移除所有映射关系(可选操作)。
boolean containsKey(Object key) 如果此映射包含指定键的映射关系,则返回 true。
boolean containsValue(Object value) 如果此映射将一个或多个键映射到指定值,则返回 true。
V get(Object key) 返回指定键所映射的值;如果此映射不包含该键的映射关系,则返回 null。
boolean isEmpty() 如果此映射未包含键-值映射关系,则返回 true。
V put(K key, V value) 将指定的值与此映射中的指定键关联(可选操作)。
void putAll(Map<? extends K,? extends V> m) 从指定映射中将所有映射关系复制到此映射中(可选操作)。
V remove(Object key) 如果存在一个键的映射关系,则将其从此映射中移除(可选操作)。
int size() 返回此映射中的键-值映射关系数。
Set<Map.Entry<K,V>> entrySet() 返回此映射所包含的映射关系的 Set 视图。

HashMap

HashMap的键要同时重写hashCode()和equals()
hashCode()用来判断确定hash值是否相同
equals()用来判断属性的值是否相同
– equals()判断数据如果相等,hashCode()必须相同
– equals()判断数据如果不等,hashCode()尽量不同
HashMap底层是一个Entry数组,当存放数据时会根据hash算法计算数据的存放位置。算法:hash(key)%n,n就是数组的长度。
当计算的位置没有数据时,就直接存放,当计算的位置有数据时也就是发生hash冲突的时候/hash碰撞时,采用链表的方式来解决的,在对应的数组位置存放链表的头结点。对链表而言,新加入的节点会从头结点加入

字符串中的字符统计

package seday12;
public class Test2_Count {
    public static void main(String[] args) {
              //abacbcda
              String s = new Scanner(System.in).nextLine();
              //a 1  b 2  c 1
              HashMap<Character,Integer> map = new HashMap<>();
              //遍历字符串获取每个字符
              for(int i = 0;i<s.length();i++) {
                     //1,取出字符串中的每个字符
                     char c = s.charAt(i);
                     //拿着字符查个数  --将该元素作为key存入map中,数量作为v存入map中
                     Integer count = map.get(c);
                     //如果取出来是null,就存1,
                     if(count==null) {
                            map.put(c, 1);  //--将该元素作为key存入map中,数量作为v存入map中
                     }else {
                          //如果取出来有值,计数加1
			               map.put(c,count+1);
                     }
              }
              System.out.println(map);
       }
}

Collections工具类

Collections.sort(List<> list):根据元素的自然顺序 对指定列表按升序进行排序。
Collections.max():根据元素的自然顺序,返回给定 collection 的最大元素。
Collections.min():根据元素的自然顺序 返回给定 collection 的最小元素。
Collections.swap(List,i,j):在指定列表的指定位置处交换元素。
Collections.addAll():
例如:
Collections.sort(list);

进程(里面包含了一个或多个线程)

就是正在运行的程序。也就是代表了程序锁占用的内存区域。
独立性
动态性:进程与程序的区别在于,程序只是一个静态的指令集合,而进程是一个正在系统中活动的指令集合
并发性:多个进程可以在单个处理器上并发执行,多个进程之间不会互相影响。
线程:操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一个进程可以开启多个线程。
一个操作系统中可以有多个进程一个进程中可以有多个线程,每个进程有自己独立的内存,每个线程共享一个进程中的内存,每个线程又有自己独立的内存

线程状态

在这里插入图片描述
线程生命周期,总共有五种状态:

  1. 新建状态(New):当线程对象对创建后,即进入了新建状态,如:Thread t = new MyThread();
  2. 就绪状态(Runnable):当调用线程对象的start()方法(t.start();),线程即进入就绪状态。处于就绪状态的线程,只是说明此线程已经做好了准备,随时等待CPU调度执行,并不是说执行了t.start()此线程立即就会执行;
  3. 运行状态(Running):当CPU开始调度处于就绪状态的线程时,此时线程才得以真正执行,即进入到运行状态。注:就绪状态是进入到运行状态的唯一入口,也就是说,线程要想进入运行状态执行,首先必须处于就绪状态中;
  4. 阻塞状态(Blocked):处于运行状态中的线程由于某种原因,暂时放弃对CPU的使用权,停止执行,此时进入阻塞状态,直到其进入到就绪状态,才有机会再次被CPU调用以进入到运行状态;
  5. 根据阻塞产生的原因不同,阻塞状态又可以分为三种:
    a) 等待阻塞:运行状态中的线程执行wait()方法,使本线程进入到等待阻塞状态;
    b) 同步阻塞:线程在获取synchronized同步锁失败(因为锁被其它线程所占用),它会进入同步阻塞状态;
    c) 其他阻塞:通过调用线程的sleep()或join()或发出了I/O请求时,线程会进入到阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入就绪状态。
  6. 结束状态(Dead):线程执行完了或者因异常退出了run()方法,该线程结束生命周期。

多线程创建

1 继承Thread --直接用自己创建的线程类new对象即可

首先 自己创建一个类 通过自己的类直接extend Thread,并重写run()方法,就可以启动新线程并执行自己定义的run()方法。
常用方法
String getName() 返回该线程的名称。
static Thread currentThread() 返回对当前正在执行的线程对象的引用。
void setName(String name) 改变线程名称,使之与参数 name 相同。
static void sleep(long millis) 在指定的毫秒数内让当前正在执行的线程休眠(暂停执行)。
void start() 使该线程开始执行;Java 虚拟机调用该线程的 run 方法。
Thread(String name) 分配新的 Thread 对象。
示例:

package seday13new;
public class Test1  {
    public static void main(String[] args) {
       //3、创建线程对象
       ThreadDemo t1 = new ThreadDemo("钢铁侠");
       ThreadDemo t2 = new ThreadDemo("美队");
       //4、开启线程:谁抢到资源谁就先执行
       t1.start();
       t2.start();
       //t1.run();//当做常规方法调用,且不会发生多线程现象
    }
}
//1、作为Thread的子类,并重写run方法。把多线程的业务写在run方法中
class ThreadDemo extends Thread{
public ThreadDemo() {}
    public ThreadDemo(String name) {
       super(name);
    }
    @Override
    public void run() {
       //2、默认实现是super.run();
       for (int i = 0; i < 10; i++) {
           System.out.println(getName()+i);
       }
    }
}
多线程创建 2:实现Runnable接口 --通过new Thread()方法传入Runnable的实现类引用对象作为参数创建线程

常用方法
void run() 使用实现接口 Runnable 的对象创建一个线程时,启动该线程将导致在独立执行的线程中调用对象的 run 方法。

package seday13new;
public class Test2 {
    public static void main(String[] args) {
       MyThread t = new MyThread ();
       //2,构造创建对象,传入Runnable子类
       Thread target = new Thread(t);
	   Thread target2 = new Thread(t);
       //开启线程
       target.start();
       target2.start();
    }
}
//1,实现Runnable接口,重写run()
class MyThread implements Runnable{
    @Override
    public void run() {
       for (int i = 0; i < 10; i++) {
       System.out.println(Thread.currentThread().getName()+" "+i);
       }
    }
}

在这里插入图片描述

多线程同步锁(提高线程安全,降低了执行效率) – 一次只让一个线程执行。通过sychronized关键字实现同步。

多线程中,**多条语句操作同一个共享数据(成员变量/类变量(static修饰))**时必须加同步锁,保证数据的一致性(别重复售卖或超卖)
语法:
synchronized(对象){
需要同步的代码;
}
特点
1、 前提1,同步需要两个或者两个以上的线程。
2、 前提2,多个线程间必须使用同一个锁。
3、 同步的缺点是会降低程序的执行效率, 为了保证线程安全,必须牺牲性能。
4、 可以修饰方法称为同步方法,使用的锁对象是this。
5、 可以修饰代码块称为同步代码块,锁对象可以任意。
售票系统–多线程同步锁示例

package seday13new;
public class Test {
    public static void main(String[] args) {
       Ticket2 t = new Ticket2();
       Thread target = new Thread(t, "窗口1");
       Thread target2 = new Thread(t, "窗口2");
       Thread target3 = new Thread(t, "窗口3");
       Thread target4 = new Thread(t, "窗口4");
	   target.start();
	   target2.start();
       target3.start();
	   target4.start();
    }
}

class Ticket2 implements Runnable {
	private int tic = 100;  //这里不需要static修饰是因为外界调用时只new一个线程对象,若是用继承Thread方式创建线程对象时,必须加static修饰为类变量,全局共享才行,因为多线程是new了多个线程对象,每一个都是100
    Object obj = new Object();
    @Override
    public void run() {
       while (true) {
       // 把有线程安全问题的代码,用同步关键字包起来
       // 原理:用一个对象作为一把锁,给代码上锁,一个线程访问锁代码时,其他线程只能等待锁释放才能进来。
       // 多线程间要使用同一把锁才可以真的把代码锁住实现线程安全。  
	   // synchronized (new Object()) {//锁了不同对象  --因为每个线程创建时都new一个对象,每new就会创建新的对象
       // synchronized (obj) {//锁了同一个对象
       //synchronized (Ticket2.class) {//锁了本类,针对于静态
           synchronized (this) {   //这是锁代码块,必须加上锁对象,若是锁方法,直接修饰方法即可锁对象不需要写
              if (tic > 0) {
                  try {
                     Thread.sleep(100);
                  } catch (InterruptedException e) {
                     e.printStackTrace();
                  }
                  System.out.println(tic--);
              }
           }
       } 
    }
}

注解

常见的元注解:@Target、@Retention
分类
l JDK自带注解5个:常用的@Override
l 元注解5个:常用的@Target、@Retention
l 自定义注解用@interface修饰类名就成了注解类
//@Target({ElementType.METHOD})//作用于方法上
//@Target({ElementType.FIELD})//作用于属性上
@Target({ElementType.METHOD , ElementType.PACKAGE})//作用范围
@Retention(RetentionPolicy.RUNTIME )//生命周期
@Target({ElementType.TYPE})//作用于类上
@interface Test{
int age() default 0;//使用时,必须给age属性赋值,如:age=X。除非设置好默认值。
//()不是参数,也不能写参数,只是特殊语法
//4,特殊属性value
String value() default “”;//使用时,必须给value属性赋值。除非设置好默认值
}

反射(Reflection)+ 内部类

反射

反射Class类对象
Class.forName(“类的全路径”);
类名.class
对象.getClass();
常用方法
获得包名、类名
clazz.getPackage().getName()//包名
clazz.getSimpleName()//类名
clazz.getName()//完整类名
成员变量定义信息 --s复数返回值数据类型都是数组结构
getFields()//获得所有公开的成员变量,包括继承的变量
getDeclaredFields()//获得本类定义的成员变量,包括私有,不包括继承的变量
getField(变量名)
getDeclaredField(变量名)
构造方法定义信息
getConstructor(参数类型列表)//获得公开的构造方法
getConstructors()//获得所有公开的构造方法
getDeclaredConstructors()//获得所有构造方法,包括私有
getDeclaredConstructor(int.class, String.class)
方法定义信息
getMethods()//获得所有可见的方法,包括继承的方法
getMethod(方法名,参数类型列表)
getDeclaredMethods()//获得本类定义的方法,包括私有,不包括继承的方法
getDeclaredMethod(方法名, int.class, String.class)
反射新建实例
clazz.newInstance();//执行无参构造
clazz.newInstance(6, “abc”);//执行有参构造
clazz.getConstructor(int.class, String.class); //执行含参构造,获取构造方法
反射调用成员变量
c.getDeclaredField(变量名); //获取变量
c.setAccessible(true); //使私有成员允许访问
f.set(实例, 值); //为指定实例的变量赋值,静态变量,第一参数给 null
f.get(实例); //访问指定实例的变量的值,静态变量,第一参数给 null
反射调用成员方法
获取方法
Method m = c.getDeclaredMethod(方法名, 参数类型列表);
m.setAccessible(true) ;//使私有方法允许被调用
m.invoke(实例, 参数数据) ;//让指定的实例来执行该方法
示例:

package seday16new;
public class Test3_ReflectPerson {
    public static void main(String[] args) throws Exception {
       Class<?> clazz = Class.forName("seday16new.Person");
//     method(clazz);//隐私属性
       method2(clazz);//执行方法
    }
    private static void method2(Class<?> clazz) throws Exception {
       Method m = clazz.getDeclaredMethod("show", int[].class);
       Object obj = clazz.newInstance();
       m.setAccessible(true);//方法隐私可见
       m.invoke(obj, new int[]{1,2,3});//执行
    }
    private static void method(Class clazz) throws Exception {
       Field f = clazz.getDeclaredField("name");
       System.out.println(f.getType().getName());
       f.setAccessible(true);//属性隐私可见
       Object obj = clazz.newInstance();
//     f.set(obj, "rose");//设置值
       System.out.println(f.get(obj));//获取值
     //---所有属性
       Field[] fs = clazz.getDeclaredFields();
       for (Field ff : fs) {
           System.out.println(ff);
           ff.setAccessible(true);//暴力反射
           System.out.println(ff.get(obj));
       }
    }
}

内部类

A类中定义了B类,B类就是内部类。B类可以当做A类的一个成员看待。
特点
1、 内部类可以直接访问外部类中的成员,包括私有成员
2、 外部类要访问内部类的成员,必须要建立内部类的对象
3、 在成员位置的内部类是成员内部类
4、 在局部位置的内部类是局部内部类

匿名内部类

匿名内部类属于局部内部类,并且是没有名字的内部类。

Socket也叫套接字编程,是一个抽象层。

应用程序可以通过它发送或接收数据,可对其像对文件一样的打开、读写和关闭等操作。套接字允许应用程序将I/O插入到网络中,并与网络中的其他应用程序进行通信。网络套接字是IP地址与端口与协议的组合。
Socket就是为网络编程提供的一种机制 / 通信的两端都有Socket
网络通信其实就是Socket间的通信 / 数据在两个Socket间通过IO传输
服务器端-ServerSocket
在服务器端,选择一个端口号,在指定端口上等待客户端发起连接。
启动服务:ServerSocket ss = new ServerSocket(端口);
等待客户端发起连接,并建立连接通道:Sokcet socket = ss.accept();
客户端-Socket
新建Socket对象,连接指定ip的服务器的指定端口
Socket s = new Socket(ip, port);
从Socket获取双向的流
InputStream in = s.getInputStream();
OutputStream out = s.getOutputStream();
说明其中,server端的accept()是阻塞的,客户端不连接,服务器不执行后面流程。
in.read()也是阻塞的,读不到就死等。
示例:
服务器端

package seday16;
public class Server {
    public static void main(String[] args) throws Exception {
       //1,在指定端口启动服务
       ServerSocket server = new ServerSocket(8000);
       //2,等待客户端发起连接,并建立通道
       Socket socket = server.accept();
       //3,取出双向的流
       InputStream in = socket.getInputStream();
       OutputStream out = socket.getOutputStream();
       //4,通信
       /*
        * 通信协议:
        * 1,通信流程
        * 2,数据格式
        * 先接收hello,再发送world
        */
       //接收客户端发来的hello
       for(int i = 0 ; i < 5 ;i++) {
           //一个一个字节从网络流中读取客户端发来的数据
           char c = (char) in.read();
           System.out.print(c);//一行展示收到的数据
       }
       //给客户端发送数据
       out.write("world".getBytes());
       out.flush();//刷出内存缓存
       //释放资源
       socket.close();//断开连接
       server.close();//释放端口
    }
}

客户端

package seday16;
public class Client {
    public static void main(String[] args) throws Exception, IOException {
       //1,与服务器建立连接
       //同桌启动服务器,你当客户端发送
       Socket s = new Socket("127.0.0.1",8000);
       //2,取出双向的流
       InputStream in = s.getInputStream();
       OutputStream out = s.getOutputStream();
       //3,通信
       /*
        * 先发送Hello,再接收world
        */
       //给服务器发送数据
       out.write("hello".getBytes());
       out.flush();
       //接收服务器响应的数据
       for (int i = 0; i < 5 ; i++) {
           char c = (char) in.read();
           System.out.print(c);//同一行展示
       }
       //释放资源
       s.close();
    }
}

本文链接http://www.taodudu.cc/news/show-1781740.html