javaweb备忘录

javase

static

  • 静态方法属于类,所以在静态方法中,无法获取成员变量的值,但是静态方法可以访问到静态变量
  • 所有被标记为静态的内容,会在类刚加载的时候就分配,而不是在对象创建的时候分配,所以说静态内容一定会在第一个对象初始化之前完成加载。

package
包类似于C++中的namespace

当前类 同一个包下的类 不同包下的子类 不同包下的类
public
protected
默认
private

类的继承

  • 标记为final的类不允许被继承:
  • 父类中将属性的访问权限修改为private,那么子类将无法访问,但是依然继承了这个属性
  • 如果父类存在一个有参构造方法,子类必须在构造方法中调用
  • 在使用子类时,可以将其当做父类来使用,也可以使用强制类型转换,将一个被当做父类使用的子类对象,转换回子类
  • a instanceof b 判断a是否是b的一个子类或者实例
  • 子类可以定义和父类同名的属性,这时可以使用super关键字来表示父类
  • 所有类都默认继承自Object类
  • a.equals(b)用于比较a,b是否是同一个对象

重写override

  • 方法的重载是为某个方法提供更多种类,而方法的重写是覆盖原有的方法实现
  • 重写方法要求与父类的定义完全一致
  • 静态方法不支持重写,因为它是属于类本身的,但是它可以被继承。
  • 我们如果不希望子类重写某个方法,我们可以在方法前添加final关键字,如果父类中方法的可见性为private,那么子类同样无法访问
  • 在重写父类方法时,如果希望调用父类原本的方法实现,那么同样可以使用super关键字
  • 子类在重写父类方法时,不能降低父类方法中的可见性,但是可以在子类中提升权限

抽象类

  • 子类,必须要实现抽象类中所有抽象方法,无法直接通过new关键字来直接创建对象
  • 抽象方法的访问权限不能为private

接口

  • 接口一般只代表某些功能的抽象,接口包含了一些列方法的定义,类可以实现这个接口,表示类支持接口代表的功能
  • 从Java8开始,接口中可以存在方法的默认实现
  • 接口中不允许存在成员变量和成员方法,但是可以存在静态变量和静态方法,接口中定义的静态变量只能是public static final
  • 接口是可以继承其他接口,相当于是对接口功能的融合

深浅复制

  • 虽然Student对象成功拷贝,但是其内层对象并没有进行拷贝,依然只是对象引用的复制,所以Java为我们提供的clone方法只会进行浅拷贝
  • 枚举类型的本质就是一个普通的类,但是它继承自Enum类,我们定义的每一个状态其实就是一个public static final的Status类型成员变量,可以给枚举类型添加独有的成员方法

包装类

  • byte -> Byte
  • boolean -> Boolean
  • short -> Short
  • char -> Character
  • int -> Integer
  • long -> Long
  • float -> Float
  • double -> Double

包装类型支持自拆装箱,可以直接将一个对应的基本类型值作为对应包装类型引用变量的值,当然也可以相反
Integer i = 10;
Integer i = 10; int a = i;
通过自动装箱转换的Integer对象,如果值相同,得到的会是同一个对象,这是因为存在IntegerCache,如果在范围内,那么会直接返回已经提前创建好的对象,IntegerCache会默认缓存-128~127之间的所有值,如果超出这个缓存范围的话,就会得到不同的对象了
BigDecimal可以实现小数和极大树的精确计算。

1
2
3
int[] array = new int[10];
类型[] 变量名称 = new 类型[]{...}; //静态初始化(直接指定值和大小)
类型[] 变量名称 = {...}; //同上,但是只能在定义时赋值
创建出来的数组每个位置上都有默认值,如果是引用类型,就是null,如果是基本数据类型,就是0,或者是false,跟对象成员变量的默认值是一样的

字符串
Java中没有字符串这种基本类型,因此只能使用类来进行定义,每个用双引号括起来的字符串,都是String类型的一个实例对象
如果是直接使用双引号创建的字符串,如果内容相同,为了优化效率,那么始终都是同一个对象
字符串的内容比较,一定要用equals
字符串和字符数组的转换
char[] chars = str.toCharArray();
String str = new String(chars);
str.matches("[abc]*")调用正则表达式进行匹配,返回bool值


成员内部类中,可以访问到外层的变量
静态内部类就像静态方法和静态变量一样,是属于类的,可以直接创建使用,但无法访问到外部类的非静态内容 不需要依附任何对象,就可以直接创建静态内部类的对象

1
2
3
4
5
6
7
public class Test 
public static class Inner {
public void test() {
System.out.println("我是静态内部类!");
}
}
}

在new的时候,后面加上花括号,内部可以定义一个匿名类Student student = new Student() {}此时创建出来的Student对象,就是一个已经实现了抽象方法的对象

Lambda表达式

  • 标准格式为:([参数类型 参数名称,]...) ‐> { 代码语句,包括返回值 }
  • 和匿名内部类不同,Lambda仅支持接口,不支持抽象类
  • 接口内部必须有且仅有一个抽象方法(可以有多个方法,但是必须保证其他方法有默认实现,必须留一个抽象方法出来)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public interface Study { 
int sum(int a, int b); //待实现的求和方法
}
public static void main(String[] args)
{
Study study = (a, b) -> a + b;
}

public static void main(String[] args)
{
Study study = (a, b) -> Integer.sum(a, b); //直接使用Integer为我们通过好的求和方法
System.out.println(study.sum(10, 20));
}
public static void main(String[] args)
{
Study study = Integer::sum; //使用双冒号来进行方法引用,静态方法使用 类名::方法名 的形式
System.out.println(study.sum(10, 20));
}

方法引用其实本质上就相当于将其他方法的实现,直接作为接口中抽象方法的实现。任何方法都可以通过方法引用作为实现
成员方法因为需要具体对象使用,所以说只能使用 对象::方法名 的形式
构造方法也可以被引用,使用new表示

所有的运行时异常都继承自RuntimeException 断言表达式需要使用到assert关键字,如果assert后面的表达式判断结果为false,将抛出AssertionError错误。

泛型
泛型在定义时并不明确是什么类型,而是需要到使用时才会确定对应的泛型类型。
public class Score<T>类似cpp的模板
因为是具体使用对象时才会明确具体类型,所以静态方法中无法使用
如果要让某个变量支持引用确定了任意类型的泛型,那么可以使用?通配符
Test<?> test = new Test<Integer>();
泛型只能确定为一个引用类型,基本类型是不支持的(不包括数组,数组本身是引用类型),如果要存放基本数据类型的值,只能使用对应的包装类
当子类实现泛型接口时,我们可以选择在实现类明确泛型类型,或是继续使用此泛型让具体创建的对象来确定类型,继承等同理

在泛型变量的后面添加extends关键字即可指定上界,使用时,具体类型只能是我们指定的上界类型或是上界类型的子类public class Score<T extends Number>
在进行类型判断时,不允许使用泛型,只能使用原始类型
泛型类不支持创建参数化类型数组(类型擦除导致的,运行时不会检查具体类型是什么)
Test<String> test = new Test<>(); System.out.println(test instanceof Test);

函数式接口
函数式接口就是JDK1.8专门为我们提供好的用于Lambda表达式的接口,这些接口都可以直接使用Lambda表达式

**Supplier供给型函数式接口:这个接口是专门用于供给使用的,其中只有一个get方法用于获取需要的对象
Consumer消费型函数式接口:这个接口专门用于消费某个对象的。
Function函数型函数式接口:这个接口消费一个对象,然后会向外供给一个对象(前两个的融合体)
Predicate断言型函数式接口:接收一个参数,然后进行自定义判断并返回一个boolean结果。

1
2
3
4
5
private static void test(String str)
{
Optional .ofNullable(str) //将传入的对象包装进Optional中
.ifPresent(s -> System.out.println("字符串长度为:"+s.length())); //如果不为空,则执行这里的Consumer实现
}

Optional
String s = Optional.ofNullable(str).get(); //get方法可以获取被包装的对象引用,但是如果为空的话,会抛出异常
String s = Optional.ofNullable(str).orElse("我是为null的情况备选方案");

java的集合类(如果两个对象使用equals方法相等,那么集合中就是相同的两个对象):

  • ArrayList

  • List,有序线性表

  • LinkedList,双向链表

  • 只要是实现了迭代器接口的类(可以自己实现),都可以使用foreach语法:

    1
    2
    3
    4
    5
    Iterator<String> iterator = list.iterator();
    while (iterator.hasNext())
    { //每次循环一定要判断是否还有元素剩余
    System.out.println(iterator.next());
    }

  • ListIterator是对list类的特化双向迭代器

  • Queue队列,Deque双向队列,其中deque有正反向的迭代器descendingIteratoriterator

  • PriorityQueue优先级队列,可以自己实现Comparator接口

  • Set集合,不允许出现重复元素,不支持随机访问

    • HashSet,哈希实现,无法维持插入顺序
    • TreeSet,元素插入时排序
  • Collections是专用于集合操作的工具类,类似Array

  • Map映射,新插入的相同键会覆盖原来的,在获取一个不存在的映射时,默认会返回null作为结果(可以设置默认值)

    • 默认不维护插入顺序,LinkedHashMap实现维护
  • Stream流水线,有点像numpy的管道

    1
    2
    3
    4
    list = list //链式调用 
    .stream() //获取流
    .filter(e -> !e.equals("B")) //只允许所有不是B的元素通过流水线
    .collect(Collectors.toList()); //将流水线中的元素重新收集起来,变回List

I/O操作

  • FileInputStream inputStream = new FileInputStream("路径");
  • inputStream.available(); //查看剩余数量
  • inputStream.read((byte[]) bytes); //一次性读取全部内容(返回值是读取的字节数)
  • 输出流使用write()类似read
  • 字符流是以一个具体的字符进行读取,因此它只适合读纯文本的文件,如果是其他类型的文件不适用FileReader | FileWriter
  • 为了避免频繁I/O,可以使用缓冲字节流BufferedInputStream缓冲字符流BufferedReader
  • 转换流InputStreamReader和OutputStreamWriter用于将字符信息转换成字节用于流的输入输出
  • 打印流PrintStream可以控制打印到的对象(向文件打印则是一个文件输出流对象),默认是控制台,Scanner默认接受系统输入流,也可以指定输入流
  • 数据流DataInputStream | dataOutputStream用于写入基本数据类型
  • 对象流ObjectOutputStream用序列化形式存储对象(也可以让某些属性不序列化),用private static final long serialVersionUID作为类的标识用于区分版本,并且用于从流式数据还原出对象

java的多线程

  • 创建Thread对象来创建一个新的线程,Thread构造方法中需要传入一个Runnable接口的实现(在另一个线程执行的内容逻辑)
  • 调用sleep()方法来将当前线程进入休眠;interrupt()方法给指定线程添加一个中断标记以告知线程需要立即停止运行或是进行其他操作,由线程来响应此中断并进行相应的处理
  • 优先级
    • MIN_PRIORITY 最低优先级
    • MAX_PRIORITY 最高优先级
    • NOM_PRIORITY 常规优先级
  • yield()方法来将当前资源让位给其他同优先级线程;使用join()方法来实现线程的加入,让一个线程等待加入的线程执行完成后再继续进行
  • synchronized关键字创造一个线程锁;jstack命令来检测死锁;
  • 对象的wait()方法会暂时使得此线程进入等待状态,同时会释放当前代码块持有的锁,这时其他线程可以获取到此对象的锁,当其他线程调用对象的notify()方法后,会唤醒刚才变成等待状态的线程(这时并没有立即释放锁)。必须是在持有锁的情况下使用
  • ThreadLocal类,来创建工作内存中的变量,不同的线程访问到ThreadLocal对象时,都只能获取到当前线程所属的变量
  • 可以通过创建一个Timer类来让它进行定时任务调度,并且该类维护TaskQueueTimerThread循环读取任务,闲则wait,调用cancel()方法来关闭工作线程
  • 其他所有的非守护线程结束之后,守护线程自动结束,守护线程中产生的新线程也是守护的t.setDaemon(true)

反射

  • 反射就是把Java类中的各个成分映射成一个个的Java对象。即在运行状态中,对于任意一个类,都能够知道这个类所有的属性和方法,对于任意一个对象,都能调用它的任意一个方法和属性。这种动态获取信息及动态调用对象方法的功能叫Java的反射机制。

  • 在Java程序启动时,JVM会将一部分类(class文件)先加载(并不是所有的类都会在一开始加载),通过ClassLoader将类加载,在加载过程中,会将类的信息提取出来(存放在元空间中,JDK1.8之前存放在永久代),同时也会生成一个Class对象存放在内存(堆内存),注意此Class对象只会存在一个,与加载的类唯一对应

  • 反射机制利用这些存放的类信息Class对象,来获取类的信息和操作类。

  • 通过反射可以对类进行精准的判断,精细区分子类,父类

  • 可以通过反射来创造类对象,调用类的方法(本质上还是类的实例进行调用)只是利用反射机制实现了方法的调用,并且这些对类的操作可以无视权限控制,也可以去除final关键字

  • 这样一来,就可以通过编译完的class文件来反向操作其中的类

注解

注解可以被标注在任意地方,与注释不同的是,注解可以通过反射在运行时获取,注解也可以选择是否保留到运行时。
可以在注解中定义一些属性,注解的属性也叫做成员变量,注解只有成员变量,没有方法。注解的成员变量在注解的定义中以“无形参的方法”形式来声明,其方法名定义了该成员变量的名字,其返回值定义了该成员变量的类型.如String value();
可以使用getAnnotations()方法来快速获取我们标记的注解。

  • @Override - 检查(仅仅是检查,不保留到运行时)该方法是否是重写方法。如果发现其父类,或者是引用的接口中并没有该方法时,会报编译错误。
  • @Deprecated - 标记过时方法。如果使用该方法,会报编译警告。
  • @SuppressWarnings - 指示编译器去忽略注解中声明的警告(仅仅编译器阶段,不保留到运行时)
  • @FunctionalInterface - Java 8 开始支持,标识一个匿名函数或函数式接口。
  • @SafeVarargs - Java 7 开始支持,忽略任何使用参数为泛型变量的方法或构造函数调用产生的警告。

元注解是作用于注解上的注解,用于我们编写自定义的注解:

  • @Retention - 标识这个注解怎么保存,是只在代码中,还是编入class文件中,或者是在运行时可以通过反射访问。
  • @Documented - 标记这些注解是否包含在用户文档中。
  • @Target - 标记这个注解应该是哪种 Java 成员。
  • @Inherited - 标记这个注解是继承于哪个注解类(默认 注解并没有继承于任何子类)
  • @Repeatable - Java 8 开始支持,标识某注解可以在同一个声明上使用多次。

java新特性

  • 8:只有一个方法要实现的类可以直接传入一个匿名函数,匿名函数的写法也可以简化,比如只有一个参数时省略括号
  • 方法引用,包括静态方法,对象的方法,构造函数等
  • Optional用于处理空指针异常
  • 9:创建一个新的项目,并在src目录下,新建module-info.java文件表示此项目采用模块管理机制,模块内部对能够对库以模块为单位调用
  • 如果模块没有明确授权给其他模块使用反射的权限,那么其他模块是不允许使用反射进行修改的,也可以用open开放反射
  • 模块可以指定对某些接口的依赖
  • jshell可以进行交互式编程
  • 接口可以提供private实现
  • 集合类可以用of方法快速创建,但创建后无法修改
  • 10:var自动类型推断,类似c++,只发生在编译期间
  • 11:全新的Http Client API,支持最新的HTTP2和WebSocket协议
  • 12-16:更简洁的switch,有类似python的yield
  • 三引号表示复杂字符串,特殊符号不需要转义
  • 类似if(obj instanceof Student student)的语法可以直接进行安全的类型转化
  • Account类可以直接提供一个有name和passwd大部分功能的类
  • 17:秘封类可以指定能继承的子类,其他类无法继承public sealed class A permits B //在class关键字前添加sealed关键字,表示此类为密封类型,permits后面跟上允许继承的类型,多个子类使用逗号隔开

gui组件

awt:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
public class better_gui {  
public static void main(String[] args) throws InterruptedException {
Frame frame = new Frame(); //Frame是窗体,我们只需要创建这样一个对象就可以了,这样就会直接创建一个新的窗口
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); //获取到屏幕尺寸
int x = (int) ((screenSize.getWidth() - frame.getWidth()) / 2); //居中位置就是:屏幕尺寸/2 - 窗口尺寸/2
int y = (int) ((screenSize.getHeight() - frame.getHeight()) / 2);
frame.setSize(500, 300); //可以使用setSize方法设定窗体大小
frame.setVisible(true); //默认情况下窗体是不可见的,我们如果要展示出来,还需要设置窗体可见性
frame.setLocation(x, y); //位置设置好了之后再展示出来
frame.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) { //windowClosing方法对应的就是窗口关闭事件
frame.dispose(); //当我们点击X号关闭窗口时,就会自动执行此方法了
//使用dispose方法来关闭当前窗口
}

@Override
public void windowClosed(WindowEvent e) { //对应窗口已关闭事件
System.out.println("窗口已关闭!"); //当窗口成功关闭后,会执行这里重写的内容
System.exit(0); //窗口关闭后退出当前Java程序
}

});
frame.addKeyListener(new KeyAdapter() {
@Override
public void keyTyped(KeyEvent e) { //监听键盘输入事件,当我们在窗口中敲击键盘输入时会触发
System.out.print(e.getKeyChar()); //可以通过KeyEvent对象来获取当前事件输入的对应字符
}
});
frame.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) { //mouseClicked是监听鼠标点击事件(必须要用真的鼠标点击,不知道为啥,笔记本的触摸板不行,可能是MacOS的BUG吧)
System.out.println("鼠标点击:" + e.getX() + "," + e.getY());
System.out.println("鼠标点击的按键:" + e.getButton());
}
});

//边界布局:
BorderLayout borderLayout = new BorderLayout();
borderLayout.setHgap(50); //Hgap是横向间距
borderLayout.setVgap(50); //Vgap是纵向间距
/* frame.add(new Button("1号按钮"), BorderLayout.WEST); //在添加组件时,可以在后面加入约束
frame.add(new Button("2号按钮"), BorderLayout.EAST);
frame.add(new Button("3号按钮"), BorderLayout.SOUTH);
frame.add(new Button("4号按钮"), BorderLayout.NORTH);
frame.add(new Button("5号按钮"), BorderLayout.CENTER);*/
//frame.setLayout(borderLayout); //使用边界布局

//流式布局:
FlowLayout flowLayout = new FlowLayout(FlowLayout.RIGHT);//采用流式布局,指定为右对齐
flowLayout.setHgap(50);
flowLayout.setVgap(0);
//frame.setLayout(flowLayout);

//卡片布局:
//CardLayout layout = new CardLayout();
/* frame.add(new Label("我是1号"));
frame.add(new Label("我是2号"));*/
frame.setVisible(true);
//frame.setLayout(layout);
/*while (true) { Thread.sleep(3000); layout.next(frame); //我们需要使用CardLayout对象来进行切换
}*/
//网格布局:
/* GridLayout gridLayout = new GridLayout();
gridLayout.setRows(2); frame.setLayout(gridLayout); for (int i = 0; i < 10; i++) frame.add(new Button(i + "号按钮"));*/

//GridBagLayout是网格布局的更自由版本

//面板是更高层的一级容器
GridLayout layout = new GridLayout(); //先设置整个窗口的布局
layout.setRows(2); //设置行数为2,一会就会分成两行了
frame.setLayout(layout);


Panel top = new Panel();
top.setBackground(Color.PINK);
top.setLayout(new FlowLayout()); //面板默认会采用FlowLayout,所以说这里指不指定都一样
for (int i = 0; i < 5; i++) //面板就像窗口一样,可以设定布局和添加组件
top.add(new Button("流式"+i));
frame.add(top);

Panel bottom = new Panel();
bottom.setBackground(Color.ORANGE);
bottom.setLayout(new GridLayout()); //下半部分我们采用网格布局
for (int i = 0; i < 5; i++)
bottom.add(new Button("网格"+i));
frame.add(bottom);

ScrollPane scrollPane = new ScrollPane(); //创建滚动面板
frame.add(scrollPane);

//滚动条
/* GridLayout layout = new GridLayout(); //创建滚动面板内部的要展示的面板
layout.setRows(20); Panel panel = new Panel(); panel.setLayout(layout); for (int i = 0; i < 20; i++) panel.add(new Button("我是按钮"+i)); //为面板添加按钮
scrollPane.add(panel);*/
//菜单
MenuBar bar = new MenuBar(); //创建菜单栏
Menu menu = new Menu("我是1号菜单");
menu.add(new MenuItem("测试1"));
menu.add(new MenuItem("测试2"));
bar.add(menu);
frame.setMenuBar(bar); //为窗口设定刚刚定义好的菜单栏
MenuItem item = new MenuItem("测试1");
item.addActionListener(e -> System.out.println("一号选项被点击了!"));
menu.add(item);
/* MenuItem item = new MenuItem("测试1");
item.setShortcut(new MenuShortcut('A')); //MenuShortcut就是指定快捷键组合,默认情况下是Ctrl+指定按键
//item.setShortcut(new MenuShortcut('A', true)); //第二个参数指定为true表示需要Ctrl+Shift+指定按键*/


/* Dialog dialog = new Dialog(frame, "我是对话框", true);
dialog.setResizable(false); dialog.add(new Label("确定是否要退出程序?"), BorderLayout.NORTH); //对话框默认采用的是边界布局
dialog.add(new Button("取消"), BorderLayout.WEST);
dialog.add(new Button("不退出"), BorderLayout.EAST);
dialog.setSize(200, 80);*/
FileDialog dialog = new FileDialog(frame, "请选择一个文件", FileDialog.LOAD);

frame.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
dialog.setVisible(true); //注意,需要将对话框展示出来之后,才能进行选择
//选择完成之后getDirectory和getFile方法就可以返回结果了,否则会阻塞
System.out.println("选择的文件为:"+dialog.getDirectory() + dialog.getFile());
}
});


}

}

swing:
Swing 是在AWT的基础上构建的一套新的图形界面系统,它提供了AWT 所能够提供的所有功能,并且用纯粹的Java代码对AWT 的功能进行了大幅度的扩充。通常把Swing控件称为轻量级控件
swing不依赖操作系统,可以跨平台实现统一的外观效果
Swing在没有设定布局时,组件的坐标原点并不是窗口的左上角,而是窗口标题栏下方的左上角:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
public class swing_gui {  
public static void main(String[] args) {
JFrame frame = new JFrame("我是窗口");
frame.setSize(500, 300);
frame.setLayout(null);
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);

JButton button = new JButton("我是按钮");
button.setBounds(0, 0, 100, 30);

frame.add(button);
frame.setVisible(true);

JMenuBar bar = new JMenuBar(); //JMenuBar对应的就是MenuBar
JMenu menu = new JMenu("我是菜单");
menu.add(new JMenuItem("选项1"));
menu.add(new JMenuItem("选项2"));
bar.add(menu);
frame.setJMenuBar(bar);
frame.setSize(500, 300);
frame.setVisible(true);

JProgressBar pbar = new JProgressBar(); //进度条显示文件拷贝进度
pbar.setMaximum(1000);
pbar.setBounds(20, 50, 300, 10);

JButton button2 = new JButton("点击开始"); //点击按钮开始拷贝文件
button2.setBounds(20, 100, 100, 30);
button2.setToolTipText("这个按钮用来复制!");
button2.addActionListener(e -> new Thread(() -> {
//注意,不能直接在这个线程里面处理,因为这个线程是负责图形界面的,得单独创建一个线程处理,否则图形界面会卡死
File file = new File("in.iso");
try(FileInputStream in = new FileInputStream(file);
FileOutputStream out = new FileOutputStream("out.iso")){
long size = file.length(), current = 0;
int len;
byte[] bytes = new byte[1024];
while ((len = in.read(bytes)) > 0) {
current += len;
pbar.setValue((int) (pbar.getMaximum() * (double)current / size)); //每次拷贝都更新进度条
pbar.repaint(); //因为并不是每次更新值都会使得组件重新绘制,如果视觉上比较卡,可以每次拷贝都重新绘制组件
out.write(bytes, 0, len);
}
} catch (IOException exception) {
exception.printStackTrace();
}
}).start());
frame.add(button2);

//这里我们让JTree展示.idea目录下所有文件
File file = new File(".idea"); //这里我们列出.idea目录下所有文件
DefaultMutableTreeNode root = new DefaultMutableTreeNode(file.getName()); //既然是树形关系,肯定有一个根结点
//拿到当前目录下所有文件和文件夹
File[] files = Optional.ofNullable(file.listFiles()).orElseGet(() -> new File[0]);
for (File f : files)
root.add(new DefaultMutableTreeNode(f.getName())); //构造子结点并连接

JTree tree = new JTree(root); //设定默认的根结点
tree.setBounds(0, 0, 200, 200);
frame.add(tree);

JTabbedPane pane = new JTabbedPane();
pane.setBounds(0, 0, 500, 300);
pane.addTab("一号", new JColorChooser()); //一号面板当颜色选择器
pane.addTab("二号", new JFileChooser()); //二号面板当文件选择器
}

}

javaweb

  • 使用PreparedStatement防止sql注入
  • 数据库的查询结果映射为java类时,为了进行类型转换需要一个无参数构造方法