【JAVA学习笔记2】
JAVA学习笔记2
- 集合 ==ArrayList==
- 代码块
- 接口 ==interface==
- 内部类 ==interface==
- 正则表达式 ==matches==
- 单列集合 ==collection==
- 迭代器==iterator==
- ==lambda表达式==
- 数据结构
- 集合 ==set==
- 哈希表 ==HashSet==
- 哈希链表 ==LinkedHashSet==
- ==TreeSet==
- ==方法引用==
- ==异常==
- 双列集合 ==Map==
- ==HashMap==
- ==LinkedHashMap==
- ==TreeMap==
- ==File==
- ==IO流==
- ==多线程==
- ==网络编程==
- ==反射==
- ==动态代理==
集合 ArrayList

集合可以存引用数据类型,不可以存基本数据类型,如果想存基本数据类型的话,需要把他们改变成对应的包装类。
ArrayList
代码块
局部代码块
public void show() {
// 局部代码块
{
String localMsg = "局部代码块内的变量";
System.out.println("6. 局部代码块执行:" + localMsg);
}
// 报错:localMsg 仅在上面的局部代码块内有效
// System.out.println(localMsg);
}
构造代码块
1、写在成员位置的代码块
2、作用:可以把多个构造方法中重复的代码抽取出来
3、执行时机:我们在创建本类对象的时候会先执行构造代码块再执行构造方法
渐渐的淘汰了,不够灵活
一般我们会用 this(null,0) 这种方式来调用本类的有参构造
静态代码块(重要)
作用:在程序刚开始的时候,做一些数据初始化
格式:static{}
特点:需要通过static关键字修饰随着类的加载而加载,并且自动触发、只执行一次
package Static_Codeblock;
public class Student {
private String name;
private int age;
// 执行时机
// 随着类的加载而加载,并且**只执行一次**
static {
System.out.println("静态代码块执行了");
}
public Student() {
System.out.println("无参构造方法执行了");
}
public Student(String name, int age) {
this.name = name;
this.age = age;
System.out.println("有参构造方法执行了");
}
接口 interface


接口中成员的特点
成员变量
------------------只能是常量
------------------默认修饰符:public static final
构造方法
------------------没有构造方法
成员方法
------------------只能是抽象方法
------------------默认修饰符:public abstract

接口实现类有构造方法,但是接口没有构造方法


内部类 interface
在一个类的里面,再定义一个类。

1、成员内部类核心是依赖外部类对象、可访问所有外部成员。
2、静态内部类核心是不依赖外部类对象、仅访问外部静态成员。
3、局部内部类核心是方法内定义、作用域仅限当前方法。
4、匿名内部类核心是无类名、一次性使用、基于父类 / 接口实现。
正则表达式 matches

单列集合 collection


Collection是单列集合的祖宗接口,它的功能是全部单列集合都可以继承使用的。
迭代器iterator
迭代器不依赖索引
如果我们要继续第二次遍历集合,只能再次获取一个新的迭代器对象


Collection<String> coll = new ArrayList<>();
coll.add("aaa");
coll.add("bbb");
coll.add("ccc");
coll.add("ddd");
// 获取迭代器
Iterator<String> it = coll.iterator();
while (it.hasNext()) {
String str = it.next();
System.out.println(str);
}
增强for循环
lambda表达式
lambda 表达式是 Java 8 引入的核心特性,本质上是匿名函数(没有名字的函数),它的核心作用是简化函数式接口的使用,让代码更简洁、更易读。
// 1. 定义函数式接口(只有一个抽象方法)
@FunctionalInterface // 可选注解,强制检查是否为函数式接口
interface Calculator {
int calculate(int a, int b);
}
public class LambdaDemo {
public static void main(String[] args) {
// 2. 传统匿名内部类写法
Calculator add1 = new Calculator() {
@Override
public int calculate(int a, int b) {
return a + b;
}
};
System.out.println(add1.calculate(10, 20)); // 输出30
// 3. lambda表达式简化写法
Calculator add2 = (a, b) -> a + b; // 单行代码,省略{}、return、分号
System.out.println(add2.calculate(10, 20)); // 输出30
// 多行代码的lambda(必须加{}和return)
Calculator multiply = (a, b) -> {
int result = a * b;
return result;
};
System.out.println(multiply.calculate(10, 20)); // 输出200
}
}
重要

数据结构






集合 set

package Set;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import java.util.function.Consumer;
public class setdemo1 {
public static void main(String[] args) {
Set<String> s = new HashSet<>();
s.add("张三");
s.add("李四");
//迭代器遍历
Iterator<String> it = s.iterator();
while (it.hasNext()) {
String str = it.next();
System.out.println(str);
}
//增强for遍历
for (String string : s) {
System.out.println(string);
}
//lambda遍历
s.forEach(new Consumer<String>() {
@Override
public void accept(String str) {
System.out.println(str);
}
});
/*
s.forEach(str ->System.out.println(str));
*/
}
}
哈希表 HashSet

1、加载因子是判断哈希表中元素数量后来扩容的,例如元素达到了12(160.75=12)个,就需要扩容到32个(162)原哈希表长度的2倍
2、JDK8以后,当链表长度超过8,而且数组长度大于等于64时,自动转换为红黑树(两个要求同时满足)
3、如果集合中存储的是自定义对象,必须要重写hashcode和equals(比对象内部的属性值)方法
哈希链表 LinkedHashSet


TreeSet

过程

compareTo

comparator

方法引用

方法引用
1.引用处需要是函数式接口
2.被引用的方法需要已经存在
3.被引用方法的形参和返回值需要跟抽象方法的形参和返回值保持一致
4.被引用方法的功能需要满足当前的要求
异常



package Exception;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class Exceptdemo1 {
public static void main(String[] args) throws ParseException {
// 编译时异常(在编译阶段,必须要手动处理,否则代码报错)
String time = "2030年1月1日";
SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日");
Date date = sdf.parse(time);
System.out.println(date); //Tue Jan 01 00:00:00 CST 2030
// 运行时异常
int[] arr = {1, 2, 3};
System.out.println(arr[10]); //ArrayIndexOutOfBoundsException
}
}

异常的作用
作用一:异常是用来查询bug的关键参考信息
作用二:异常可以作为方法内部的一种特殊返回值,以便通知调用者底层的执行情况
try catch

package Exception;
public class Exceptdemo2 {
public static void main(String[] args) {
int[] arr = {1, 2, 3};
try {
// 可能出现异常的代码
System.out.println(arr[10]);
// 此处出现了异常,程序会在这里创建一个ArrayIndexOutOfBoundsException对象
// new ArrayIndexOutOfBoundsException();
// 拿着这个对象到catch的小括号中对比,看括号中的变量是否可以接收这个对象
// 如果能被接收,就表示该异常就被捕获(抓住),执行catch里面对应的代码
// 当catch里面所有的代码执行完毕,继续执行try...catch体系下面的其他代码
} catch (ArrayIndexOutOfBoundsException e) {
// 如果出现了ArrayIndexOutOfBoundsException异常,我该如何处理
System.out.println("索引越界了");
}
// 好处:可以让程序继续执行,不会停止
System.out.println("程序继续执行");
}
}

对可能出现异常的代码按crtl + alt + t 可以补全try/catch代码

throw / throws

package Exception;
public class Exceptdemo3 {
public static void main(String[] args) {
/*
throws:写在方法定义处,表示声明一个异常。告诉调用者,使用本方法可能会有哪些异常。
throw :写在方法内,结束方法。手动抛出异常对象,交给调用者。方法中下面的代码不再执行了。
需求:
定义一个方法求数组的最大值
*/
int[] arr = {};
int max = 0;
try {
max = getMax(arr);
} catch (NullPointerException e) {
System.out.println("空指针异常");
}
catch (ArrayIndexOutOfBoundsException e) {
System.out.println("越界异常");
}
System.out.println(max);
}
public static int getMax(int[] arr)/* throws NullPointerException, ArrayIndexOutOfBoundsException*/{
if (arr == null) {
// 手动创建一个异常对象,并把这个异常交给方法的调用者处理
// 此时方法就会结束,下面的代码不会再执行了
throw new NullPointerException();
}
if(arr.length == 0){
// 手动创建一个异常对象,并把这个异常交给方法的调用者处理
// 此时方法就会结束,下面的代码不会再执行了
throw new ArrayIndexOutOfBoundsException();
}
System.out.println("执行了吗");
int max = arr[0];
for (int i = 0; i < arr.length; i++) {
if (max < arr[i]) {
max = arr[i];
}
}
return max;
}
}

需求:
键盘录入自己心仪的女朋友姓名和年龄。
姓名的长度在 3 - 10之间,
年龄的范围为 18 - 40岁,
超出这个范围是异常数据不能赋值,需要重新录入,一直录到正确为止。
提示:
需要考虑用户在键盘录入时的所有情况。
比如:录入年龄时超出范围,录入年龄时录入了abc等情况
package Exception;
import java.util.Scanner;
public class test {
public static void main(String[] args) {
/*
需求:
键盘录入自己心仪的女朋友姓名和年龄。
姓名的长度在 3 - 10之间,
年龄的范围为 18 - 40岁,
超出这个范围是异常数据不能赋值,需要重新录入,一直录到正确为止。
提示:
需要考虑用户在键盘录入时的所有情况。
比如:录入年龄时超出范围,录入年龄时录入了abc等情况
*/
// 1、创建键盘录入的对象
Scanner sc = new Scanner(System.in);
// 2、创建女朋友对象
girlfriend gf = new girlfriend();
while (true) {
// 3、接受女朋友的姓名
try {
System.out.println("请输入女朋友的姓名:");
String name = sc.nextLine();
gf.setName(name);
// 4、接受女朋友的年龄
System.out.println("请输入女朋友的年龄:");
String ageStr = sc.nextLine();
// 将字符串类型的数字转换为 int 整数
int age = Integer.parseInt(ageStr);
gf.setAge(age);
// 如果所有的数据都是正确的,那么跳出循环
break;
} catch (NumberFormatException e) {
System.out.println("年龄格式需要是数字");
e.printStackTrace();
} catch (NameFormatException e) {
e.printStackTrace();
} catch (AgeOutBoundException e) {
e.printStackTrace();
}
}
// 5、打印
System.out.println(gf);
}
}
双列集合 Map


put方法的细节:
添加/覆盖
在添加数据的时候,如果键不存在,那么直接把键值对对象添加到map集合当中,方法返回null
在添加数据的时候,如果键是存在的,那么会把原有的键值对对象覆盖,会把被覆盖的值进行返回
HashMap

核心点:
HashMap的键位置果存储的是自定义对象,需要重写hashcode和equals方法。
package Map;
import java.util.HashMap;
import java.util.Set;
import java.util.Map;
public class HashMapdemo1 {
public static void main(String[] args) {
/*
需求:创建一个HashMap集合,键是学生对象(student),值是籍贯(string)。
存储三个键值对元感,并遍历
要求:同姓名,同年龄认为是同一个学生
核心点:
HashMap的键位置果存储的是自定义对象,需要重写hashcode和equals方法。
*/
// 1、创建HashMap的对象
HashMap<Student, String> hm = new HashMap<>();
// 2、创建3个学生对象
Student s1 = new Student("zhansan", 23);
Student s2 = new Student("lisi", 24);
Student s3 = new Student("wangwu", 25);
// 3、添加元素
hm.put(s1, "北京");
hm.put(s2, "上海");
hm.put(s3, "广州");
// 4、遍历集合
Set<Student> keys = hm.keySet();
for (Student key : keys) {
String value = hm.get(key);
System.out.println(key + "=" + value);
}
System.out.println("-------------------------------");
// 5、使用entrySet() 增强for循环
Set<Map.Entry<Student, String>> entries = hm.entrySet();
for (Map.Entry<Student, String> entry : entries) {
Student key = entry.getKey();
String value = entry.getValue();
System.out.println(key + "=" + value);
}
System.out.println("-------------------------------");
// 6、hm调用foreach方法
hm.forEach(((student,s)-> System.out.println(student + "=" + s)));
}
}
LinkedHashMap
package Map;
import java.util.LinkedHashMap;
public class LinkedHashMapdemo2 {
public static void main(String[] args) {
/*
LinkedHashMap:
由键决定:
有序、不重复、无索引。
有序:
保证存储和取出的顺序一致
原理:
底层数据结构是依然哈希表,只是每个键值对元素又额外的多了一个双链表的机制记录存储的顺序。
*/
// 1、创建集合
LinkedHashMap<String,Integer> lhm = new LinkedHashMap<>();
// 2、添加元素
lhm.put("a", 123);
lhm.put("a", 123);
lhm.put("b", 456);
lhm.put("c", 789);
// 3、打印集合
System.out.println(lhm);
}
}
TreeMap

package Map;
import java.util.Comparator;
import java.util.TreeMap;
public class TreeMapdemo3 {
public static void main(String[] args) {
/*
TreeMap集合:基本应用
需求1:
键: 整数表示id
值: 字符串表示商品名称
要求1: 按照id的升序排列
要求2: 按照id的降序排列
*/
// Integer Double 默认情况下都是按照升序排列的
// string按照字母再ASCII码表中对应的数字升序进行排列
// 要求1: 按照id的升序排列
TreeMap<Integer,String> tm = new TreeMap<>();
tm.put(1, "小李");
tm.put(3, "小王");
tm.put(2, "小张");
tm.put(5, "小赵");
tm.put(4, "小孙");
System.out.println(tm);
// 要求2: 按照id的降序排列
TreeMap<Integer,String> tm2 = new TreeMap<>(new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
// o1:当前要添加的元素
// o2:表示已经在红黑树中存在的元素
return o2 - o1;
}
});
tm2.put(1, "小李");
tm2.put(3, "小王");
tm2.put(2, "小张");
tm2.put(5, "小赵");
tm2.put(4, "小孙");
System.out.println(tm2);
}
}
自定义异常

File
构造方法

IO流
存储和读取数据的解决方案
多线程



创建新执行线程有两种方法。
一种方法是将类声明为 Thread 的子类。该子类应重写 Thread 类的 run 方法。接下来可以分配并启动该子类的实例。
另一种方法是声明实现 Runnable 接口的类。该类然后实现 run 方法。然后可以分配该类的实例,在创建 Thread 时作为一个参数来传递并启动。
继承Thread类的方式进行实现
package Thread;
public class Mythread extends Thread {
@Override
public void run() {
// 书写线程要执行代码
for (int i = 0; i < 100; i++) {
System.out.println(getName() + "HelloWorld");
}
}
}
package Thread;
public class Threaddemo1 {
public static void main(String[] args) {
/*
多线程的第一种启动方式:
1.自己定义一个类继承 Thread
2.重写run方法
3.创建子类的对象,并启动线程
*/
Thread t1 = new Mythread();
Thread t2 = new Mythread();
t1.setName("线程1");
t2.setName("线程2");
t1.start();
t2.start();
}
}
实现Runnable接口的方式进行实现
package Thread;
public class MyRun implements Runnable{
@Override
public void run() { // t1 t2
// 书写线程要执行代码
for (int i = 0; i < 100; i++) {
// 获取到当前线程的对象
Thread t = Thread.currentThread();
System.out.println(t.getName() + "HelloWorld");
}
}
}
package Thread;
public class Threaddemo2 {
public static void main(String[] args) {
/*
多线程的第二种启动方式:
1.自己定义一个类实现Runnable接口
2.重写里面的run方法
3.创建自己的类的对象
4.创建一个Thread类的对象,并开启线程
*/
MyRun mr = new MyRun();
Thread t1 = new Thread(mr);
Thread t2 = new Thread(mr);
t1.setName("线程1");
t2.setName("线程2");
t1.start();
t2.start();
}
}
利用Callable接口和Future接口方式实现
package Thread;
import java.util.concurrent.Callable;
public class MyCallable implements Callable<Integer>{
@Override
public Integer call() throws Exception {
int sum = 0;
for (int i = 0; i <= 100; i++) {
// System.out.println(Thread.currentThread().getName() + ":" + i);
sum += i;
}
return sum;
}
}
package Thread;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
public class Threaddemo3 {
public static void main(String[] args) throws ExecutionException, InterruptedException {
/*多线程的第三种实现方式:
特点:可以获取到多线程运行的结果
1.创建一个类MyCallable实现callable接口
2.重写ca11 (是有返回值的,表示多线程运行的结果)
3.创建MyCallable的对象(表示多线程要执行的任务)
4.创建FutureTask的对象(作用管理多线程运行的结果)
5.创建Thread类的对象,并启动(表示线程)
*/
MyCallable mc = new MyCallable();
FutureTask<Integer> ft = new FutureTask<>(mc);
Thread t1 = new Thread(ft);
t1.start();
// 获取多线程运行结果
Integer result = ft.get();
System.out.println(result);
}
}

网络编程

反射
反射允许对封装类的字段,方法和构造函数的信息进行编程访问。

package Reflect;
public class MyReflectdemo1 {
public static void main(String[] args) throws ClassNotFoundException {
/*
获取class对象的三种方式:
1.Class.forName("全类名");
2.类名.class
3.对象.getclass();
*/
// 1、第一张方式
// 最为常用的
Class clazz1 = Class.forName("Reflect.Student");
// 2、第二张方式
Class clazz2 = Student.class;
// 3、第三张方式
// 当我们已经有了这个类的对象时,才可以使用。
Student s = new Student();
Class clazz3 = s.getClass();
System.out.println(clazz1 == clazz2);
System.out.println(clazz2 == clazz3);
}
}
// 1. 普通方式(编译期必须知道类名,无法动态调整)
Student s = new Student();
s.setName("张三");
System.out.println(s.getName());
// 2. 反射方式(运行时动态操作,类名可通过字符串传入)
public static void reflectDemo() throws Exception {
// 步骤1:获取Class对象(类的"镜像")
Class<?> clazz = Class.forName("com.example.Student"); // 字符串类名,可动态传入
// 步骤2:动态创建对象(无参构造)
Object obj = clazz.newInstance();
// 步骤3:获取并调用setName方法(即使是private也能调用)
Method setNameMethod = clazz.getDeclaredMethod("setName", String.class);
setNameMethod.setAccessible(true); // 突破private访问限制
setNameMethod.invoke(obj, "张三");
// 步骤4:获取并调用getName方法
Method getNameMethod = clazz.getDeclaredMethod("getName");
getNameMethod.setAccessible(true);
String name = (String) getNameMethod.invoke(obj);
System.out.println(name); // 输出:张三
}
动态代理
特点:无侵入式的给代码增加额外的功能

package DynamicProxy;
public class BigStar implements Star{
private String name;
public BigStar() {
}
public BigStar(String name) {
this.name = name;
}
// 唱歌
@Override
public String sing(String name) {
System.out.println(this.name + "正在唱" + name);
return "谢谢";
}
// 跳舞
@Override
public void dance() {
System.out.println(this.name + "正在跳舞");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "BigStar{" +
"name='" + name + '\'' +
'}';
}
}
package DynamicProxy;
public interface Star {
// 唱歌
public abstract String sing(String name);
// 跳舞
public abstract void dance();
}
package DynamicProxy;
/*
* 类的作用:
* 创建一个代理
*/
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class ProxyUtil {
public static Star createProxy(BigStar bigstar) {
Star star = (Star) Proxy.newProxyInstance(
ProxyUtil.class.getClassLoader(),
new Class[]{Star.class},
new InvocationHandler(){
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if("sing".equals(method.getName())){
System.out.println("准备话筒,收钱");
}else if("dance".equals(method.getName())){
System.out.println("准备场地,收钱");
}
return method.invoke(bigstar, args);
}
}
);
return star;
}
}
package DynamicProxy;
public class Test {
public static void main(String[] args) {
// 创建一个被代理对象
BigStar bigstar = new BigStar("鸡哥");
// 创建一个代理对象
Star Proxy = ProxyUtil.createProxy(bigstar);
String result = Proxy.sing("只因你太美");
System.out.println(result);
Proxy.dance();
}
}
结果:
准备话筒,收钱
鸡哥正在唱只因你太美
谢谢
准备场地,收钱
鸡哥正在跳舞
完结撒花!!!
更多推荐





所有评论(0)