Java篇
数据类型:
本质 就是规定占用内存空间的大小,用位和字节表示
引用数据类型
类,数组,接口
基本数据类型
数值型
整数型
byte,short,int,long
浮点型
float,double
布尔型
boolean
字符型
char
Bit : 比特,1bit就是一个电子位,统称位
Byte : 字节 , 1字节= 8bit 8位
Short : 短整型 , 1short= 16bit
Int : 整型 ,1int = 32bit
Long : 长整型 , 1long=64bit
Float : 单浮点 32位
Double : 双浮点 64位
Boolean : 布尔型 ,4位 0001 true, 0000 false
Char : 字符 , 16位 ,
ASCII 码是字符和整型直接的一个映射关系
0 : 48
1 : 49
A : 65
B : 66
a : 97
c : 98
变量
:常量/字面量/直接量
- 常量:在程序整个声明周期不可变
- 字面量:直接量如System.out.prtinln(123);
- 变量:有名字的内存空间,可以找到,更改,访问。可以重复使用(强制 : 大小写字母,数字,下划线,美元符号,数字不能开头,不能使用关键字和保留字
非强制 : 驼峰命名法,望文知文件名,变量名,方法名,类名,包名(文件夹名) 一切需要我们命名的地方,都要符合这个规则)
流程控制、循环、方法
流程控制
- 顺序结构
正常编码,从上往下,从左到右执行即可
2.分支结构
根据业务逻辑,某些代码在某种情况下执行
或者是根据不同的情况执行不同的代码
技术栈 : if…else … switch
递归
学好递归要了解程序的运行机制
1 java程序编写
文本编辑器
2 java程序编译
Javac 命令
3 Java程序的执行
Java 命令
3.1 开启java虚拟机,载入对应的class文件,载入到静态区
3.2 jvm自动调用main方法
3.3 main被调用,JVM会在栈内存开辟一个main的空间,用于执行main中的代码
如果main中没有其他方法调用,执行完就弹栈,结束,JVM关闭
如果main方法中有其他方法调用,就会在栈内存再次开辟栈帧,把对应的方法放入栈内存,开始执行
如果被调用方法中还有其他方法调用,同上
一直到某一个方法栈中,没有其他方法调用,该方法如果代码执行完成,则该栈帧弹栈,如果需要返回数据,会占用临时空间把数据传递回去
弹栈后 返回上一个栈帧中方法调用处,继续执行
一直到main方法弹栈,则整个栈帧调用链结束.JVM关闭
栈内存是真正执行程序的地方,其他内存都是存储数据
方法调用 就等于是 压栈操作
方法执行结束 就等于是 弹栈操作
动态加载和静态加载
动态加载 : 只载入当前程序和需要的文件,如果执行过程中需要别的文件,再去硬盘中找
静态加载 : 开始执行,把所有和当前程序相关的文件,全部一次性载入
方法体内部对当前方法进行调用
常见问题
斐波那契数列:
package day_4;
/**
* 声明一个方法,接收一个参数 判断传递的参数值再斐
* 波那契数列的第几位上 如果不存在 打印 -1 , 如果存在 打印对应的位数
*
* @author moon
*
*/
public class Feb {
public static void main(String[] args) {
num(3);
System.out.println(m(4));
}
//循环
public static void num(int n) {
if (n == 1 || n == 2) {
System.out.println("1");
}
int i1 = 1;
int i2 = 1;
int i3 = 0;
for (int i = 3; i <= n; i++) {
i3 = i1 + i2;
i1 = i2;
i2 = i3;
}
System.out.println(i3);
}
//递归
public static int m(int a) {
if (a == 1 || a == 2) {
return 1;
}
//m(a)=m(a - 1) + m(a - 2)
return m(a - 1) + m(a - 2);
}
}
实现代码:写一个递归方法,输入一个非负整数, 返回组成它的数字之和.
package day_4;
public class Recursion_4 {
public static void main(String[] args) {
// 实现代码:写一个递归方法,输入一个非负整数,
// 返回组成它的数字之和.
System.out.println(sum(437856621));
}
public static int sum(int a) {
if (a < 9) {
return a;
} else {
return a % 10 + sum(a / 10);
}
}
}
**
数组
**
经典排序
冒泡法
package test;
//
public class Test3 {
public static void main(String[] args) {
// 冒泡排序
int[] a = { 91, 14, 6, 8, 923, 12 };
System.out.println(m(a));
}
//冒泡排序
public static int m(int a[]) {
for(int i=0;i<a.length-1;i++){
for(int j=0;j<a.length-1-i;j++){
if(a[j]>a[j+1]){
int temp=a[j];
a[j]=a[j+1];
a[j+1]=temp;
}
}
}
return a[a.length-1];
}
//选择排序
}
二分法
package test;
public class Work6 {
public static void main(String[] args) {
// 给出一个有序数组
// int a[] ={1,3,4,5,6,7,9,15,17,19,38,41,52,63,73,78};
// 请编写二分查找,查询 9在第几位上,如果没有请返回-1
int a[] = { 1, 3, 4, 5, 6, 7, 9, 12,15, 17, 19, 38, 41, 52, 63, 73, 78 };
int result=search(a,78);
System.out.println(result+1);
}
public static int search(int[] a,int num){
int start=0;
int end=a.length-1;
int m=(start+end)/2;
while(start<=end){
if(num==a[m]){
return m;
}else if(num>a[m]){
start=m+1;
//start开始查询后半段
}else{
end=m+1;
//end开始查询前半段
}
m=(start+end)/2;
}
return -1;
}
}
选择排序
package work;
public class Work1 {
public static void main(String[] args) {
int[] a = { 11, 13, 4, 5, 12 };
selectSort(a);
for (int i = 0; i < a.length; i++) {
System.out.println(a[i]);
}
}
// 11,13,4,5,12 i = 0, min = 2
// 13,4,11,5,12 i = 1, min = 0
// 13,11,4,5,12 i = 2, min = 1
// 13,11,5,4,12 i = 3, min = 2
// 13,11,5,12,4 i = 4, min = 3
// 13,11,5,12,4 i = 5, min = 3
public static void selectSort(int[] a) {
for (int i = 0; i < a.length; i++) {
// 假设 第一个元素是最小的
int min = i;
// min+1 是因为 没有必要自己跟自己比较
// j 不能从0开始,否则结果不对
for (int j = i + 1; j < a.length; j++) {
// 循环一次之后,x是最小元素的下标
if (a[min] > a[j]) {
min = j;
}
}
// 判断 min 是否等于 i ,如果等于i 说明 i 就是最小的,如果不是 说明有比 i 还小的,就换位
if (min != i) {
int temp = a[min];
a[min] = a[i];
a[i] = temp;
}
}
}
}
**
面向对象
**
面向对象和面向过程
面向过程 : 侧重分步骤
比如做饭 :
1 买食材
2 开火
3 加水…放米…
4 熟了
面向对象 : 侧重分类/模块
比如做饭 :
找个厨师
厨师.买食材
厨师.开火
厨师.加水…方米…
面向对象和面向过程都是解决问题的思路,或者是程序设计范型,只是侧重点不同
面向对象的基础也是面向过程,只是面向对象把具体的实现细节给封装了,让外界无法直接获取
优点 :
易于维护、可扩展性、可重用性
方法有哪些,是什么
this、封装、继承
传值和传引用,
传引用,传递的是地址,如果地址传递到另一个地方,则拥有相同地址的变量,可以找到同一个对象,那么操作的数据也是相互的
This,不能出现在静态上下文中
链式调用
继承extends
Java中只支持单继承,不支持多继承,这样使继承关系比较简单,一个类 只有一个父类,易于程序管理,当然为了解决单继承功能变弱的问题,java又提出了接口,一个类可以实现N个接口
如果一个类,没有显示继承几个父类的话,则该类默认继承java.lang.Object
不管如何继承,最终任何类都直接/间接的成为Object的子类
Object是java提供的根类(祖宗)
抽象方法
package duotai;
public class Abstract {
public static void main(String[] args) {
}
}
abstract class A{
public A(){
}
//没有方法体的成员方法,需要用abstract修饰
public abstract void move1();
public abstract void move2();
public void m1(){
System.out.println("父类的m1");
}
}
abstract class C extends A{
public abstract void move3();
}
class D extends C{
@Override
public void move3(){
//
}
@Override
public void move1(){
}
@Override
public void move2(){
}
}
class B extends A{
@Override
public void move1(){
}
@Override
public void move2(){
}
}
- 1 懒汉模式
- 2 饿汉模式
- 实现步骤 :
-
既然要控制创建对象的数量,就不能让用户去决定是否创建对象
-
而创建对象的语句是 new 构造方法() ; , 通过构造方法创建对象,
- 而我们不让用户创建对象
-
所以 应该不让用户访问构造方法,应该把构造方法私有化,
- 这样创建对象的决定权就在当前类中
- 1 构造方法私有化
-
上面步骤,已经把构造方法私有化了,就意味着用户创建不了对象了
-
那么这个时候,我们还需要想办法把该对象返回给用户,
- 也就是必须提供一个专门获取这
对象的方法 -
这个方法,一定是公共的静态方法
- 2 创建一个公共的静态方法,用户获取当前类的对象,并且保证只创建一次
*获取对象的方法有了,下面就是要保证对象的唯一性了,想要重复使用(唯一) 必须先存储
*存储方式 : 需要创建一个当前类类型的变量
*局部 变量 : 不行,因为每次调用该方法的时候,该变量都会重新初始化赋值
*静态 变量 : 没问题,因为静态在整个程序生命周期中只初始化一次
*成员 变量 : 不行,因为静态上下文中无法引用非静态属性 - 3 创建一个私有化静态变量,用来存储当前类的对象
* 下面程序 : 类加载阶段创建对象 叫饿汉模式
public class Sing1 {
//创建一个私有化静态变量,存储当前类的对象
private static Sing1 obj=new Sing1();
//构造方法私有化
private Sing1(){
System.out.println("Sing1");
}
//创建一个公共的静态方法,用户获取当前类的对象
public static Sing1 getInstance(){
return obj;
}
}
* 懒汉模式 : 第一次使用的时候,再创建对象
*/
public class Sing2 {
private static Sing2 obj=null;
private Sing2(){
System.out.println("Sing2");
}
public static Sing2 getInstance(){
if(obj==null){
obj=new Sing2();
}
return obj;
}
}
**
常用API
**
String:
- String 是字符串类 , 在 java.lang.String , 所以使用不需要导包
- 底层就是一个char数组,所以字符串很多特性就是数组特性
- 数组特性 : 查询更改快,添加删除慢, 长度一旦确定不可更改
-
字符串一旦确定 不能更改
为了提升字符串的效率,java提供了一个"缓存机制",字符串常量池
//char数组转字符串
char[] chars={'a','c','c','d','e'};
String s5=new String(chars);
//截取部分
String s6=new String(chars,3,2);
System.out.println(s6);
//获取字符串某个位置的字
String s1="asdfgh";
char c1=s1.charAt(2);
System.out.println(c1);
package _01String;
public class String4 {
public static void main(String[] args){
//获取字符串某个位置的字
String s1="asdfgh";
char c1=s1.charAt(2);
System.out.println(c1);
//返回长度
int l=s1.length();
System.out.println(l);
//判断字符串是否以指定字符串结束
//是否以指定字符开始
System.out.println("asddfdsf".endsWith("f"));
System.out.println("afsdfadsf".startsWith("afs"));
//比较两个字符串是否相等
System.out.println("ads".equals("Ads"));
System.out.println("ads".equalsIgnoreCase("Ads"));
//把字符串转换为字节数组
byte[] bytes="Abc".getBytes();
for(byte a:bytes){
System.out.println(a);
}
//获取指定字符串的起始索引下标,找不到返回 -1
System.out.println("adfdfsadfbc".indexOf("d"));
//获取最后一次出现的索引,找不到返回 -1
System.out.println("adfdfsadfbc".lastIndexOf("d"));
//在指定位置开始找,第一次出现的索引,找不到返回-1
System.out.println("asfuox".indexOf("o", 4));
System.out.println("asfuox".lastIndexOf("o", 5));
// 把符合条件的字符用指定字符替换(不支持正则表达式)
System.out.println("ffdagdgdffdsae".replace("f", "."));
// 把符合条件的字符用指定字符替换(支持正则表达式)
System.out.println("fFfdagdgdffdsae".replaceAll("f", "."));
// 分割字符串,需要指定分隔符,支持正则表达式
String time="13331,111,22";
String[] s=time.split(",");
for(String a:s){
System.out.println(a);
}
//获取该字符串的子字符串(下标是起始位置,包含)
System.out.println("afdadf".substring(2));
// 截取字符串,开始位置(包含) 结束位置(不包含)
System.out.println("afdadf".subSequence(1, 4));
// 把字符串转换为char数组
char[] chars="acva".toCharArray();
for(char c:chars){
System.out.println(c);
}
//转大写和小写
System.out.println("asdf".toUpperCase());
System.out.println("asdf".toUpperCase().toLowerCase());
//两边去空格
System.out.println(" x sdffsd ".trim());
// 调用对象的toString方法,并解决空指针异常
Object obj=null;
//obj.toString();
System.out.println(obj);
}
}
操作字符串的类有:String、StringBuffer、StringBuilder。
String 和 StringBuffer、StringBuilder 的区别在于 String 声明的是不可变的对象,每次操作都会生成新的 String 对象,然后将指针指向新的 String 对象,而 StringBuffer、StringBuilder 可以在原有对象的基础上进行操作,所以在经常改变字符串内容的情况下最好不要使用 String。
StringBuffer 和 StringBuilder 最大的区别在于,StringBuffer 是线程安全的,而 StringBuilder 是非线程安全的,但 StringBuilder 的性能却高于 StringBuffer,所以在单线程环境下推荐使用 StringBuilder,多线程环境下推荐使用 StringBuffer。
package _01String;
/* java.lang.String
* java.lang.StringBuffer
* java.lang.StringBuilder
* 1 String 是不可变的字符串,一旦确定 长度不能更改,所以不适合做拼接操作
* 2 StringBuffer和StringBuilder 是可变的字符串缓冲区,适合做拼接操作
* 原理 : 预先在内存中申请一块空间,用来容纳更多的字符(字符数组)
* 如果预留空间不够 会自动扩容,默认容量是16个字符
*
* 3 StringBuffer和StringBuilder的区别
*StringBuffer 线程安全,多线程环境下,没有问题,所以经常用于类中
*StringBuilder 非线程安全,多线程环境下,可能有问题,所以经常用于方法中
*
*/
public class String6 {
public static void main(String[] args) {
//创建对象
StringBuilder sb=new StringBuilder();
//添加
sb.append("a");
sb.append("b");
//插入指定位置
sb.insert(2, "c");
System.out.println(sb.length());
System.out.println(sb);
//返回当前的容量value.length。默认是16,
//容量是新插入字符的可用存储量,否则将进行分配。
System.out.println(sb.capacity());
//转换为字符串
String s=sb.toString();
System.out.println(s);
// 反转
System.out.println(sb.reverse());
}
}
package _01String;
public class String8 {
public static void main(String[] args) {
//创建对象
StringBuilder sb=new StringBuilder();
//添加
sb.append("d");
sb.append("e");
//插入指定位置
sb.insert(2, "f");
System.out.println(sb.length());
System.out.println(sb);
System.out.println(sb.capacity());
//转换为字符串
String s=sb.toString();
System.out.println(s);
// 反转
System.out.println(sb.reverse());
}
}
date
package _03Data;
import java.text.SimpleDateFormat;
import java.util.Date;
public class Date3 {
public static void main(String[] args) {
SimpleDateFormat sdf = new SimpleDateFormat("HH:mm");
Date date = new Date();
String time = sdf.format(date);
String[] times = time.split(":");
int h = Integer.parseInt(times[0]);
int m = Integer.parseInt(times[1])-10;
if (m < 0) {
h--;
m += 60;
}
System.out.println(h + ":" + m);
// 获取当前时间毫秒数
long currentTimeMillis = System.currentTimeMillis();
// 减去10分钟的毫秒数
currentTimeMillis = currentTimeMillis - 1000 * 60 * 10;
// 创建时间对象
SimpleDateFormat dds=new SimpleDateFormat("yyyy/MM/dd HH:mm:ss SSS");
Date t=new Date(currentTimeMillis);
String str=dds.format(t);
System.out.println(str);
}
}
常见的数据结构及特征
ArrayList:既然是一串连续的存储结构,所以方便查找。新增和删除操作的时候,是要有移动位置的操作。所以ArrayList适用于存储,查询操作比较频繁的数据存储
package Test;
import java.util.ArrayList;
/*有序,可重复
有指定下标,添加顺序和取出顺序一致
ArrayList : 底层是个Object[] 数组,随机查询效率高,随机删除效率低,默认初始化时10,扩大之后是原来的1.5倍,并且是第一次添加数据的时候进行默认长度设置,只new的时候,不添加数据,则长度为0, 等于是 Object[] elementData= {}; 长度为0
LinkedList : 底层是双向链表,随机查询效率低,随机删除效率高
Vector : 已经过时,属于线程安全,而ArrayList是Vector的升级版 , 默认初始化是10,扩大之后是原来的2倍
*/
public class Collection_03_Arraylist {
public static void main(String[] args) {
ArrayList list = new ArrayList();
// 尾部添加
list.add(1);
list.add(2);
list.add(5);
// 添加到指定位置
list.add(0, 8);
// 更改指定元素的值
list.set(1, 11);
// get : 根据索引 获取值
System.out.println(list.get(1));
// 个数
System.out.println(list.size());
// 是否包含(调用equals)
System.out.println(list.contains(2));
System.out.println(list);
// 注意 : remove有方法重载,一个int (要删除的索引) 一个 object(要删除的数据)
// 这个2 是删除的索引,并不是要删除2这个元素
list.remove(1);
// 这样才是删除2这个数据
list.remove(new Integer(2));
System.out.println(list);
}
}
LinkedList:LinkedList底层使用的是双向循环链表数据结构,不适合存储需要大量查询操作的数据存储,插入就比ArrayList方便,不需要进行换位操作。
package Test;
import java.util.LinkedList;
/*队列 : 先到先得 , 栈 : 先进后出
*
* 链表 : 链表中保存节点,而一个节点有三部分 1 添加的数据 2 上一个节点 3 下一个节点
* 链表是没有下标的,只能从头一个个找,所以查找慢
* 由于链表中 都是引用指向,所以删除快, 比如 3个元素 分别是 1,2,3 要删除 2 ,
* 只需要让 1 的下一个 = 1 的下一个的下一个 然后 3 的上一个 = 1的引用
*
* LinkedList是模拟的双向链表,就是 1 可以找到 2 , 2 也能找到 1
*
* 添加指定位置 / 获取指定位置的值 : 可以传入索引,但是其实不是下标,而是LinkedList封装的方法,帮我们自动循环去找
* 本质 还是循环,因为链表是非连续的空间,只能从头一个一个找,
* 只不过LinkedList模拟了下标访问的方式,对我们使用起来,提供了便捷
*/
public class Collection_05LinkedList {
public static void main(String[] args) {
LinkedList linkedList = new LinkedList();
// 尾部添加 true
linkedList.add(1);
// 尾部添加 void
linkedList.addLast(2);
// 插入指定位置
linkedList.add(0,2);
// 首部添加 void
linkedList.addFirst(2);
// 首部添加 void
linkedList.push(3);
// 尾部添加 true
linkedList.offer(22);
// 首部添加 true
linkedList.offerFirst(1);
// 尾部添加 true
linkedList.offerLast(4);
// 本质就是在调用两个方法 : linkLast 和 linkFirst
// 根据下标获取
System.out.println(linkedList.get(0));
System.out.println(linkedList.get(0));
// 获取首元素
System.out.println(linkedList.getFirst());
// 获取尾元素
System.out.println(linkedList.getLast());
// 删除第一个元素,并返回该元素
linkedList.pop();
// 删除最后一个元素,并返回该元素
linkedList.poll();
// remove重载 int是根据索引删除, Object 是根据内容删除
linkedList.remove(1);
linkedList.remove( new Integer(22) );
}
}
TreeSet:底层数据结构是二叉树有序的,并且没有重复元素。可以指定一个顺序。
package Test_01;
import java.util.Set;
import java.util.TreeSet;
/**16
* 1 要添加的原始 实现 java.lang.Comparable接口 并实现compareTo方法
* 2 写一个比较器类,实现java.util.Comparator比较器接口
*
* 很多常用的类中都实现了Comparable接口 并实现compareTo方法
* 比如 Integer , String , Date等
*
* 所以我们自定义类型的时候,一定要弄比较器类
*/
public class TreeSet_02 {
public static void main(String[] args) {
Set set=new TreeSet();
set.add(new User(19,"saf"));
//重复就不会添加
set.add(new User(29,"saf"));
set.add(new User(19,"saff"));
set.add(new User(14,"sf"));
System.out.println(set);
}
}
class User implements Comparable {
int age;
String name;
public User(int age, String name) {
super();
this.age = age;
this.name = name;
}
@Override
public String toString() {
return "User [age=" + age + ", name=" + name + "]";
}
@Override
public int compareTo(Object o) {
//this是要添加的元素
//o是集合中的每一个元素
//返回值是0说明重复,不添加
//返回值大于0的值,说明要添加的这个元素比集合中的元素大,往后放
//返回小于0的值,说明要添加的元素比集合中的元素小,往后放
if(o instanceof User){
User user=(User)o;
int result=age-user.age;
if(result==0){
if(name.equals(user.name)){
return 0;
}else{
return 1;
}
}
return result;
}
return 0;
}
}
HashSet:链表和红黑树,元素没有顺序(底层用的是HashMap,HashMap本身中的元素度没有顺序)、元素不能重复。
HashMap:链表和红黑树,Null可以做主键,但只能有一个,可以有多个Value为Null。适用于在Map中插入、删除和定位元素。
package Test_01;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
public class Map_02 {
/**
* 17 map和集合虽然没有关系,但是操作几乎是一样的
*
* 添加 : Object put(Object key , Object value); void clear() : 清空map int
* size() boolean isEmpty()
*
*
* Object get(Object key) : 根据key 获取value Collection values() :
* 获取所有的value,返回集合 boolean containsKey(Object key) : 判断是否包含某个key boolean
* containsVallue(Object value) : 判断是否包含某个value Set keySet() :
* 把map中所有的key取出,返回set Set entrySet() : 把键值对保存entry中,以set形式返回 V
* remove(Object key) : 根据key删除映射,返回value值
*
* map不能直接遍历
*
*/
public static void main(String[] args) {
Map<String,Integer> map=new HashMap<String,Integer>();
map.put("a", 1);
map.put("b", 2);
map.put("c", 7);
map.put("d", 4);
map.put("e", 5);
System.out.println(map);
//keySet
Set<String> keys=map.keySet();
for(String key:keys){
Integer value=map.get(key);
System.out.println(key+":"+value);
}
//entrySet
Set<Entry<String,Integer>>entrys=map.entrySet();
for(Entry<String,Integer>entry:entrys){
String key=entry.getKey();
Integer value=entry.getValue();
System.out.println(key+":"+value);
}
}
}
TreeMap:有序的,适用于按自然顺序或自定义顺序遍历键(key)。
LinkedHashMap:有序、Key和Value都允许空、Key重复会覆盖、Value允许重复
Vector:Vector是线程安全的,可以由多个线程访问一个Vector对象。但当一个线程访问的话,保证线程安全会消耗一定的资源。一个线程访问就无需考虑是否线程安全的问题,使用ArrayLis.
Map转list 并以value排序
package Test_01;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
public class MapToList {
public static void main(String[] args) {
Map<String, Integer> map = new HashMap<String, Integer>();
map.put("aa", 3);
map.put("bb", 2);
map.put("dd", 1);
map.put("cc", 12);
// 转换为set
Set<Entry<String, Integer>> set = map.entrySet();
//转换为list
List <Entry<String, Integer>> list = new ArrayList<Map.Entry<String,Integer>>(set);
//排序
Collections.sort(list,new Comparator<Entry<String, Integer>>() {
@Override
public int compare(Entry<String, Integer> o1,
Entry<String, Integer> o2) {
return o1.getValue() - o2.getValue();
}
});
// 遍历
for (Entry<String, Integer> entry : list) {
System.out.println(entry);
}
}
}
**
IO流
**
流是一组有顺序的,有起点和终点的字节集合,是对数据传输的总称或抽象。即数据在两设备间的传输称为流,流的本质是数据传输,根据数据传输特性将流抽象为各种类,方便更直观的进行数据操作。
文件的复制
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
public class _05Cooy_all {
/**19
* 1 文件复制 : 本质就是输入和输出
* 1 完成文件输入
* 2 完成文件输出
* 3 把输入读取到的数据,通过输出流输出(把打印到控制台,换成输出流的写出即可)
* 2 获取指定目录下所有子目录
* 1 获取目录对象
* 2 获取该目录的直接子目录
* 3 获取该目录的所有后代目录(遍历子目的,得到孙目录,在遍历.....)
* 3 整合所有后代目录和文件复制
* 1 获取到所有后代目录的文件对象
* 2 通过文件对象获取文件的全路径
* 3 判断目标全路径目录是否存在,不存在就创建
* 4 通过全路径就可以创建输入流和输出流
* 5 输出
*/
public static void main(String[] args) {
//被复制目标路径
File file = new File("E:\\0");
checkMenu(file);
System.out.println("完成");
}
public static void checkMenu(File f){
// 判断是否是文件
if (f.isFile()) {
// 获得全路径
String filePath = f.getAbsolutePath();
// 设置新路径 设置关键是substring
String newFilePath = "E:/copy"+filePath.substring(2);
// 判断目标目录是否存在
File parentFile = new File(newFilePath).getParentFile();
if (!parentFile.exists()) {
// 不存在就递归创建
parentFile.mkdirs();
}
// 到这里 目标目录 一定存在
try (
FileInputStream fis = new FileInputStream(filePath);
FileOutputStream fos = new FileOutputStream(newFilePath);
BufferedInputStream bis = new BufferedInputStream(fis);
BufferedOutputStream bos = new BufferedOutputStream(fos);
){
byte[] bytes = new byte[10240000];
int tmp = 0;
while ((tmp = bis.read(bytes)) != -1) {
bos.write(bytes, 0, tmp);
}
bos.flush();
} catch (Exception e) {
e.printStackTrace();
}
return;
}
// 不是文件就获取它所有的子文件,再把所有的子文件递归传入
File[] fs = f.listFiles();
for (File file : fs) {
checkMenu(file);
}
}
}
代码优化 降低低耦合
package Work_01;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
/**
* 19 多文件内容合并读问题: 任意给定多个文本文件路径合并为一个大的文本文件, 并保存名为merge.txt。
* 1)、如给定"one.txt”,“two.txt”,“three.txt"三个文本文件路径
* 2)、内部分别存储内容"内容One"、“内容Two”、“内容Three"
* 3)、合并完成后merge.txt的结果为三行文字,分别为“内容One"、"内容Two"、"内容Three"
*/
public class IO_MergeThree {
public static void main(String[] args) throws IOException {
// 写入内容
FileWriter fw = new FileWriter("E:/a/one.txt");
fw.write("内容One");
fw.flush();
FileWriter fw2 = new FileWriter("E:/b/two.txt");
fw2.write("内容Two");
fw2.flush();
FileWriter fw3 = new FileWriter("E:/c/three.txt");
fw3.write("内容Three");
fw3.flush();
// 写出merge
FileWriter os = new FileWriter("E:/merge.txt");
// 添加缓冲流
BufferedReader bs1 = new BufferedReader(new FileReader("E:/a/one.txt"));
BufferedReader bs2 = new BufferedReader(new FileReader("E:/b/two.txt"));
BufferedReader bs3 = new BufferedReader(new FileReader("E:/c/three.txt"));
BufferedWriter bo = new BufferedWriter(os);
// 第一次输出
char[] c0 = new char[1024];
int tem0 = 0;
while ((tem0 = bs1.read(c0)) != -1) {
// 字节输出
bo.write(new String(c0, 0, tem0));
}
bo.write("\n");
bo.flush();
// 第二次输出
char[] c1 = new char[1024];
int tem1 = 0;
while ((tem1 = bs2.read(c1)) != -1) {
// 字节输出
bo.write(c1, 0, tem1);
}
bo.write("\n");
bo.flush();
// 第三次输出
char[] c2 = new char[1024];
int tem2 = 0;
while ((tem2 = bs3.read(c2)) != -1) {
// 字节输出
bo.write(c2, 0, tem2);
}
bo.flush();
}
}
package Work_01;
/**
* 1 编码实现一个压缩包a.rar文件的复制。
*/
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class IO_01_copy {
public static void main(String[] args) throws IOException {
//读取
FileInputStream is = new FileInputStream("E:/work/a.rar");
//写出
FileOutputStream os = new FileOutputStream("E:/a.rar");
//添加缓冲流
BufferedInputStream bs=new BufferedInputStream(is);
BufferedOutputStream bo=new BufferedOutputStream(os);
byte[] bytes = new byte[10240];
int tem = 0;
while ((tem = bs.read(bytes)) != -1) {
//字节输出
bo.write(bytes, 0, tem);
}
bo.flush();
}
}
package Work_01;
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
import java.util.Set;
import java.util.TreeSet;
/**19
* 文件input.txt中存放着10行数字,为0至6区间的整数,
* 求10行数字去重后还有多少行?分别是哪些数字?排序序出。
*/
public class IO_list {
public static void main(String[] args) throws IOException {
//添加缓冲流
BufferedReader bi=new BufferedReader(new FileReader("E:/input.txt"));
//添加Set比较
TreeSet<Integer> li=new TreeSet<Integer>();
String tem=null;
//字符串存储读取
byte[] bytes=new byte[10240];
while((tem=bi.readLine())!=null){
li.add(Integer.parseInt(tem));
}
System.out.println("去重后剩余"+li.size()+"行");
System.out.println(li);
}
}
**
线程池
**
package _01_Test;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* 1 减少创建和销毁次数
*
* 2 可以重复使用
*
* 3 统一管理线程数量
*/
public class _05_NewCachedThreadPool {
public static void main(String[] args) {
// 创建一个可缓存的线程池
// 若没有可以回收的,就创建新的线程,线程池规模没有限制,数量不固定
ExecutorService cachExecutorService = Executors.newCachedThreadPool();
for (int i = 0; i < 10; i++) {
// 循环创建,并且都在线程中睡眠一秒,会创建10个线程
cachExecutorService.execute(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName());
}
});
}
//此时上面10个线程都已执行完成,有线程空闲,不会新建线程
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 执行任务
cachExecutorService.execute(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName());
}
});
System.out.println("OOOO");
// 关闭线程池
cachExecutorService.shutdown();
}
}
网络编程
概述
Java是 Internet 上的语言,它从语言级上提供了对网络应用程 序的支持,程序员能够很容易开发常见的网络应用程序。
Java提供的网络类库,可以实现无痛的网络连接,联网的底层 细节被隐藏在 Java 的本机安装系统里,由 JVM 进行控制。并 且 Java 实现了一个跨平台的网络库,程序员面对的是一个统一 的网络编程环境
lambda表达式
基本使用
package test;
import java.util.Arrays;
import java.util.List;
import java.util.stream.IntStream;
import java.util.stream.Stream;
/**
* 23
* 通过Stream.generate : 是一个无限流(无限大),
* 再操作的时候,通过limit进行最大数量控制
* 常用的转换算子 : filter,distinct,map,limit,skip,flatMap
*
* filter : 对元素进行过滤筛选,不符合条件的不要
*
* distinct : 去除重复
*
* skip : 跳过多少个元素
*
* limit : 取一个集合中的 前几个数据
*
* map : 在集合的遍历中对数据进行操作,比如更改,公司所有员工薪水涨10%
*
* flatMap : 解决字符串数组
*/
public class Stream_01 {
public static void main(String[] args) {
//数组 创建 Stream.of
String[] strings = {"a","s","d","f","g","h"};
Stream<String> stream1 = Stream.of(strings);
//通过集合
List<String> strings2 = Arrays.asList(strings);
Stream<String> stream2 = strings2.stream();
// 参数 Supplier,有一个get方法,是无参有返回值
// get方法的返回值 就作为集合中的数据,下面这中就等于都赋值为1
Stream<Integer> generate = Stream.generate(()->1);
//使用limit 设置元素个数
generate.limit(4).forEach(x->System.out.println(x));
//Stream.Iterate 来创建
// 是一个有序的无限流,所以建议使用limit进行最大数量控制
// 第一个参数是数据的起始值,第二个参数是Function,所以是有参有返回值
// 1 就是起始值是1 , x+2 步长为2 , 就类似于一个死循环,起始值是1,步长为2
Stream<Integer> iterate = Stream.iterate(1, x->x+2);
iterate.limit(3).forEach(x->System.out.println(x));
//通过已有类API
String str = "badsfasd";
IntStream chars = str.chars();
chars.forEach(x->System.out.println(x));
}
}
应用
package test;
/**
24 1. 找出2011年发生的所有交易,并按交易额排序(从低到高)
2. 交易员都在哪些不同的城市工作过
3. 查找所有来自剑桥的交易员,并按姓名排序
4. 返回所有交易员的姓名字符串,按字母顺序排序
5. 有没有交易员是在米兰工作的?
6. 所有交易中,最高的交易额是多少
7. 找到交易额最小的交易
*/
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class Work_01 {
public static List<Transaction> transactions = null;
static {
Trader raoul = new Trader("Raoul", "Cambridge");
Trader mario = new Trader("Mario", "Mqilan");
Trader alan = new Trader("Alan", "Cambridge");
Trader brian = new Trader("Brian", "Cambridge");
transactions = Arrays.asList(new Transaction(brian, 2011, 300),
new Transaction(raoul, 2012, 1000), new Transaction(raoul,
2011, 400), new Transaction(mario, 2012, 710),
new Transaction(mario, 2012, 700), new Transaction(alan, 2012,
950));
}
public static void main(String[] args) {
// 1. 找出2011年发生的所有交易,并按交易额排序(从低到高)
Stream<Transaction> stream1 = transactions.stream();
stream1.filter(tran -> tran.getYear() == 2011)
.sorted((x, y) -> x.getValue() - y.getValue())
.forEach(x -> System.out.println(x));
System.out.println("------------------------------");
// 2. 交易员都在哪些不同的城市工作过
stream1 = transactions.stream();
stream1.map(x -> x.getTrader().getCity()).distinct()
.collect(Collectors.toList())
.forEach(x -> System.out.print(x + " "));
System.out.println();
System.out.println("---------------------------------");
// 3. 查找所有来自剑桥的交易员,并按姓名排序
stream1 = transactions.stream();
List<Transaction> value1 = stream1.filter(
x -> x.getTrader().getCity().equals("Cambridge")).collect(
Collectors.toList());
System.out.println(value1);
System.out.println("---------------------------------");
// 4. 返回所有交易员的姓名字符串,按字母顺序排序
stream1 = transactions.stream();
List<String> value2 = stream1.map(x -> x.getTrader().getName())
.distinct().collect(Collectors.toList());
value2.sort((x, y) -> x.compareTo(y));
System.out.println(value2);
System.out.println("---------------------------------");
// 5. 有没有交易员是在米兰工作的?anyMatch
stream1 = transactions.stream();
if (stream1.anyMatch(x -> x.getTrader().getCity().equals("Milan"))) {
System.out.println("有");
} else {
System.out.println("没有");
}
System.out.println("---------------------------------");
// 6. 打印生活在剑桥的交易员的所有交易额
stream1 = transactions.stream();
List<Integer> value3 = stream1
.filter(x -> x.getTrader().getCity().equals("Cambridge"))
.map(x -> x.getValue()).collect(Collectors.toList());
System.out.println(value3);
System.out.println("---------------------------------");
// 7. 所有交易中,最高的交易额是多少max
Integer value4 = transactions.stream().map(x -> x.getValue())
.max((x, y) -> Integer.compare(x, y)).get();
System.out.println(value4);
System.out.println("---------------------------------");
// 8. 找到交易额最小的交易 min
Optional<Transaction> value5 = transactions.stream().min(
(x, y) -> x.getValue() - y.getValue());
System.out.println(value5);
}
}
// 商人
class Trader {
private String name;
private String city;
public Trader() {
}
public Trader(String name, String city) {
this.name = name;
this.city = city;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
@Override
public String toString() {
return "Trader{" + "name='" + name + '\'' + ", city='" + city + '\''
+ '}';
}
}
// 交易
class Transaction {
private Trader trader;
private int year;
private int value;
public Transaction() {
}
public Transaction(Trader trader, int year, int value) {
this.trader = trader;
this.year = year;
this.value = value;
}
public Trader getTrader() {
return trader;
}
public void setTrader(Trader trader) {
this.trader = trader;
}
public int getYear() {
return year;
}
public void setYear(int year) {
this.year = year;
}
public int getValue() {
return value;
}
public void setValue(int value) {
this.value = value;
}
@Override
public String toString() {
return "Transaction{" + "trader=" + trader + ", year=" + year
+ ", value=" + value + '}';
}
}
sql篇
sql综合测试
course表
teacher表
sc表
student表
学生表 Student
create table Student(Sid varchar(6), Sname varchar(10), Sage datetime, Ssex varchar(10));
insert into Student values('01' , '赵雷' , '1990-01-01' , '男');
insert into Student values('02' , '钱电' , '1990-12-21' , '男');
insert into Student values('03' , '孙风' , '1990-05-20' , '男');
insert into Student values('04' , '李云' , '1990-08-06' , '男');
insert into Student values('05' , '周梅' , '1991-12-01' , '女');
insert into Student values('06' , '吴兰' , '1992-03-01' , '女');
insert into Student values('07' , '郑竹' , '1989-07-01' , '女');
insert into Student values('08' , '王菊' , '1990-01-20' , '女');
成绩表 SC
create table SC(Sid varchar(10), Cid varchar(10), score decimal(18,1));
insert into SC values('01' , '01' , 80);
insert into SC values('01' , '02' , 90);
insert into SC values('01' , '03' , 99);
insert into SC values('02' , '01' , 70);
insert into SC values('02' , '02' , 60);
insert into SC values('02' , '03' , 80);
insert into SC values('03' , '01' , 80);
insert into SC values('03' , '02' , 80);
insert into SC values('03' , '03' , 80);
insert into SC values('04' , '01' , 50);
insert into SC values('04' , '02' , 30);
insert into SC values('04' , '03' , 20);
insert into SC values('05' , '01' , 76);
insert into SC values('05' , '02' , 87);
insert into SC values('06' , '01' , 31);
insert into SC values('06' , '03' , 34);
insert into SC values('07' , '02' , 89);
insert into SC values('07' , '03' , 98);
课程表 Course
create table Course(Cid varchar(10),Cname varchar(10),Tid varchar(10));
insert into Course values('01' , '语文' , '02');
insert into Course values('02' , '数学' , '01');
insert into Course values('03' , '英语' , '03');
教师表 Teacher
create table Teacher(Tid varchar(10),Tname varchar(10));
insert into Teacher values('01' , '张三');
insert into Teacher values('02' , '李四');
insert into Teacher values('03' , '王五');
– 1查询在 SC 表存在成绩的学生信息
SELECT * from student s INNER JOIN (SELECT Sid from sc) c on s.Sid=c.Sid GROUP BY Sname;
– 2 查询所有同学的学生编号、学生姓名、选课总数、所有课程的总成绩(没成绩的显示为 null )
select * from student s left JOIN (SELECT Sid,COUNT(Sid) num,SUM(score) sum from sc GROUP BY Sid)c on s.Sid=c.Sid GROUP BY s.Sname;
– 3查有成绩的学生信息
select * from student s inner JOIN (SELECT Sid,COUNT(Sid) num,SUM(score) sum from sc GROUP BY Sid)c on s.Sid=c.Sid GROUP BY s.Sname;
– 4 查询「李」姓老师的数量
SELECT COUNT(*) from teacher WHERE Tname LIKE '李%';
– 5查询学过「张三」老师授课的同学的信息
SELECT * FROM student st INNER JOIN(SELECT Sid from sc s INNER JOIN (SELECT Tname,Tid from teacher) t on s.Cid=t.Tid WHERE t.Tname='张三')a on st.Sid=a.Sid;
– 6查询没有学全所有课程的同学的信息
select * from student s left JOIN (SELECT Sid,COUNT(Sid) num,SUM(score) sum from sc GROUP BY Sid)c on s.Sid=c.Sid GROUP BY s.Sname HAVING num<>3 or num is null;
– 7查询和” 01 “号的同学学习的课程完全相同的其他同学的信息
select * from student where sid in (select b.sid from sc b where b.sid
not in (select a.sid from sc a where a.cid not in
(select cid from sc where sid = '01')) and b.sid <> '01' group by b.sid
having count(*) = (select count(*) from sc where sid = '01'));
–8查询至少有一门课与学号为” 01 “的同学所学相同的同学的信息
select * from student where sid in (SELECT Sid from sc where Cid in (SELECT cid from sc WHERE Sid='01'));
– 9查询没学过”张三”老师讲授的任一门课程的学生姓名
SELECT * from student WHERE Sid not in(select Sid FROM sc where Cid='03' GROUP BY Sid);
– 10 查询两门及其以上不及格课程的同学的学号,姓名及其平均成绩
SELECT Sname,s.Sid,s.ave from student st INNER JOIN(SELECT Sid,avg(score)ave from sc WHERE score<60 GROUP BY Sid HAVING COUNT(*)>=2)s on st.Sid=s.Sid;
– 11 检索” 01 “课程分数小于 60,按分数降序排列的学生信息
SELECT * from student where Sid in(SELECT Sid from sc where score<60 and Cid='01' ORDER BY score desc);
– 12按平均成绩从高到低显示所有学生的所有课程的成绩以及平均成绩
SELECT Sid,avg(score)ave from sc GROUP BY Sid ORDER BY ave desc;
SELECT Sid,GROUP_CONCAT(Cid,'=',score ORDER BY score desc SEPARATOR ' | ')s_score,avg(score) ave from sc
GROUP BY Sid;
– 13 查询各科成绩最高分、最低分和平均分
SELECT c.Cid,c.Cname,MAX(score),MIN(score),avg(score) from sc s
INNER JOIN (SELECT Cid,Cname from course)c on s.Cid=c.Cid GROUP BY c.Cid;
– 14 统计各科成绩各分数段人数:课程编号,课程名称,[100-85],[85-70],[70-60],[60-0] 及所占百分比
select s.Cid,C.Cname,
((select COUNT(*) from sc where Cid=c.Cid and score>=85 and score<=100)/(select COUNT(*)from sc where Cid=c.Cid)) '100-85',
((select COUNT(*) from sc where Cid=c.Cid and score>=70 and score<85)/(select COUNT(*)from sc where Cid=c.Cid)) '85-70',
((select COUNT(*) from sc where Cid=c.Cid and score>=60 and score<=70)/(select COUNT(*)from sc where Cid=c.Cid)) '70-60',
((select COUNT(*) from sc where Cid=c.Cid and score>=0 and score<=60)/(select COUNT(*)from sc WHERE Cid=c.Cid)) '60-0'
from sc s INNER JOIN course c on s.Cid=c.Cid GROUP BY s.Cid
– 15 查询出只选修两门课程的学生学号和姓名
SELECT s.Sid,st.Sname from sc s INNER JOIN (SELECT Sid,Sname from student)st on s.Sid=st.Sid GROUP BY Sid HAVING COUNT(1)=2
–16 查询名字中含有「风」字的学生信息
SELECT * from student WHERE Sname like '%风%'
-17 查询 1990 年出生的学生名单
SELECT * from student WHERE Sage like '1990%'
– 18 成绩不重复,查询选修「张三」老师所授课程的学生中,成绩最高的学生信息及其成绩
SELECT DISTINCT *,MAX(score) FROM student st INNER JOIN(SELECT Sid,score from sc s INNER JOIN (SELECT Tname,Tid from teacher) t on s.Cid=t.Tid WHERE t.Tname='张三')a on st.Sid=a.Sid;
– 19查询各学生的年龄,只按年份来算
select *,round(datediff(CURRENT_DATE(),sage)/365) as age from student
– 20按照出生日期来算,当前月日 < 出生年月的月日则,年龄减一
SELECT *,TIMESTAMPDIFF(year,s.sage,CURRENT_DATE()) AS age FROM student s