第一天:
1windows:
---微软 优点:流畅 缺点:蓝屏+安全性差
linux
---server操作系统
win+r打开运行对话框
notepad记事本 画图mspaint 计算器calc
.exe可执行文件 .class编译后的文件
windiws优化:1、停止不必要的进程
2、停止不必要的服务 --打开服务services.msc
3、调整最佳性能 --设置视觉效果选项卡 调整为最佳性能
4、桌面个性化 --windows经典
5、修改虚拟内存 --50%
栈:先进后出 系统的窗口就是栈结构
进制转换:https://jingyan.baidu.com/article/495ba84109665338b30ede98.html
16进制:0 1 2 3 4 5 6 7 8 9 A B C D E F 以0x开头
0xfe
1、dos命令:dir cd \ d:切换盘符 dir /? 显示帮助 . 当前目录 .. 上级目录 cls 清屏 mkdir创建目录 exit退出 type 显示内容
echo >重定向 覆盖操作 echo >>重定向 追加操作 del删除目录 tree使用树形结构显示文件系统盘 set查看环境变量
2、环境变量
1、java_home 供基于java的软件寻找jdk的执行程序所用
name:java_home
value:c:\download\jdk.1.8.0-65
2、path
name:path
value:%java_home%\bin;......
3、classpath:搜索类的目录顺序
name:classpath
value: %java_home%\bin;%java_home%\lib\tools.jar;
4、重启命令行
5、java -version 查看版本
6、验证是否ok:在任何目录下输入 javac,查看输出结果
运行HelloWorld : javac编译 javac HelloWorld.java
java运行 java HelloWorld
第二天
jvm
jre=jvm(java开发工具包)+核心类库
jdk=jre+开发工具
面向对象:继承 封装 多态
进制转换
负数的表现形式:补码(取反+1)
8种基本类型 byte 1字节=8位 -128~127
short 2字节 -32768~32767 65535
int 4字节
long 8字节
float 4字节
double 8字节
boolean 1字节
char 2字节 \u0000-\uffff
3种引用类型:数组 class interface
特殊字符 \t制表 \r换行 \n回车
精度丢失问题
s+=5与s=s+5的区别
答:s+=5是进行自动类型转换的,
比如说我们在编写Java程序的时候,有时候会发现定义一个short型的变量s,
short s = 4;
然后s = s+5报错,而s+=5却没有问题,这是怎么回事呢。
因为5是整型数,占4个字节,而short占2个字节,当s+5的时候,s为short型会转为int型与5运算,可是结果却要赋给精度低的short型,会丢失精度。所以会报错,编译不通过
但是s+=5这一运算不同,就是一次运算,只有一次赋值运算,会自动转换,编译通过。
instance判断对象是否是指定的类型,后面跟的是引用类型
它的作用是测试它左边的对象是否是它右边的类的实例,返回boolean类型的数据。举个例子: String s = "I AM an Object!"; boolean isObject = s instanceof Object;
我们声明了一个String对象引用,指向一个String对象,然后用instancof来测试它所指向的对象是否是Object类的一个实例,显然,这是真的,所以返回true,也就是isObject的值为True。
&逻辑与与&&短路与的区别 :& 左边无论真假,右边都进行运算 && 如果左边为真,右边参与运算,如果左边为假,则右边不参与运算
false&true都判断 false&&true
^问:
异或:相同二进制进行运算 相同为0,不同为1
为什么 & |没有短路?
-128存储形式?
计算机中0是整数还是负数:负数
成绩float 用switch写出 优良中差 与不及格
打印直角三角形 空心三角形 乘法表
//空心三角形
public static void print6(int size){
for(int i=1;i<=size;i++){
if(i==size){//第一行等于最后一行
for(int j=0;j<2*size-1;j++){
System.out.print("*");//打印*
}
}else{
for(int j=1;j<=size-i;j++){//打印空格
System.out.print(" ");
}
for(int k=1;k<=2*i-1;k++){//第一行到最后一行
if(k==1||k==2*i-1){ //第一行或最后一行
System.out.print("*");
}else{
System.out.print(" ");//中间打印空格
}
}
System.out.println();
}
}
}
//菱形
public static void print5(int n) {
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n - i; j++) {
System.out.print(" ");
}
for (int k = 1; k <= 2 * i - 1; k++) {
System.out.print("*");
}
System.out.println();
}
for (int i = 1; i < n; i++) {
for (int j = 1; j <= i; j++) {
System.out.print(" ");
}
for (int k = 1; k <= (n - i) * 2 - 1; k++) {
System.out.print("*");
}
System.out.println();
}
}
左移<<和右移>>
三目运算符:System.out.println(b<40?"小于":"不小于");
比较三个数的大小,可嵌套
int x=5; int y=6;int z=7;
System.out.println( x>y?(x>z?x:z):(y>z?y:z));
switch 语句可选择的类型 byte short int char
在jdk1.7版本以前,参数类型只能是short、byte、int、char可正常运行。而例如String,Long、Integer、double、float等则会报错。
而jdk1.7版本以后,参数类型除了之前可使用的外,String、Integer类、 Character类、枚举类型都可以正常运行。而Long、double、float依旧会报错。
while与for的区别:for循环定义的变量在for循环结束时就在内存中释放,while循环使用的变量在循环结束后还可以继续使用
第三天
方法:具有特定功能的一段独立小程序
方法的格式
调用方法
前n项和
public static void He(int n){
int sum =0;
for(int i=0;i<=n;i++){
sum=sum+i;
}
}
动态乘法表
pubclic static void table(int row){
for(int i=1;i<=row;i++){
for(int j=1;j<=i;j++){
System.out.print(j+"*"+i+"="+(i*j)+"\t");
}
System.out.println(\r\n);
}
}
计算阶乘
public static int fabric(int n){
if(n<=0){
return -1;
}
int res=1;
for(int i=1;i<=n;i++){
res=res*i;
}
return res;
}
}
递归 rescursive
public static int fac(int n){
if(n=1){
return 1;
}
return n * fac(n-1);
}
}
数组:同一种数据类型的集合。
数组的定义 类型[] 变量名=new 类型[数值] 数组的长度固定 int [] a=new int[10]; int[] a={1,2,3}
length()是属性,不是方法
定义数组,并直接初始化 int[] arr=new int[] {1,2,3};
// 水仙花数 方法2:
// public class Task{
// public static void main(String[] ags){
// for(int shu=100;shu<1000;shu++){
// if(Math.pow(shu/100,3)+Math.pow(shu%100/10,3)+Math.pow(shu%10,3)==shu){
// System.out.println(shu+"水仙花数");
//
// }
// }
//
// }
问:提取数组元素最大值
public static int getMax(int[] arr){
if(arr==null||arr.length==0){
return -1;
}
int max=arr[0];
for(int i=1;i<arr.length;i++){
max=max>arr[i]?max:arr[i]
}
}
栈:方法在栈中,方法的调用链条 存储局部变量,数据使用完,所占空间会自动释放
堆:对象和数组在堆中;是jvm最大的内存空间
冒泡排序:每一次选出当前元素中最大的数放在末尾
public static void maoPao(int[] arr) {
for (int i = 0; i < arr.length - 1; i++) {//外层循环控制排序趟数
for (int j = 0; j < arr.length - 1 - i; j++) {//内层循环控制每一趟排序多少次
if (arr[j] > arr[j + 1]) {
int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
for (int ii : arr) {
System.out.println(ii);
}
}
选择排序:在要排序的一组数中,选出最小的一个数与第一个位置的数交换;然后在剩下的数当中再找最小的与第二个位置的数交换,
public static void selectSort(int [] arr){
for(int i=0;i<arr.length;i++){
for(int j=i+1;j<arr.length;j++){
if(arr[i]>arr[j]){
int temp=arr[i];
arr[i]=arr[j];
arr[j]=temp;
}
}
}
}
public static void print(int [] arr){
for(int i=0;i<arr.length;i++){
System.out.println(arr[i]+" ");
}
}
}
折半查找(二分法)
public class Demo1 {
/**
* * A:案例演示
* 数组高级二分查找代码
* B:注意事项
* 如果数组无序,就不能使用二分查找。
* 因为如果你排序了,但是你排序的时候已经改变了我最原始的元素索引。
*/
public static void main(String[] args) {
int[] arr = {11,22,33,44,55,66,77};
System.out.println(getIndex(arr, 22));
System.out.println(getIndex(arr, 66));
System.out.println(getIndex(arr, 88));
}
/*
* 二分查找
* 1,返回值类型,int
* 2,参数列表int[] arr,int value
*/
public static int getIndex(int[] arr, int value) {
int min = 0;
int max = arr.length - 1;
int mid = (min + max) / 2;
while(arr[mid] != value) { //当中间值不等于要找的值,就开始循环查找
if(arr[mid] < value) { //当中间值小于了要找的值
min = mid + 1; //最小的索引改变
}else if (arr[mid] > value){ //当中间值大于了要找的值
max = mid - 1; //最大的索引改变
}
mid = (min + max) / 2; //无论最大还是最小改变,中间索引都会随之改变
if(min > max) { //如果最小索引大于了最大索引,就没有查找的可能性了
return -1; //返回-1
}
}
return mid;
}
输出一个整数的二进制
public static int byteScope(byte b){
return b&xxff;
}
public static void putIntBinaryString(int n){
for(int i=31;i>= 0;i--){
System.out.print((n>>i)&0x1);
}
System.out.println();
}
二维数组 :九宫格
第三天
1、把一个数组的元素放进另一个数组里,可截断
public static void arrayCopy(int [] arr1,int [] arr2){
if(arr1.length>arr2.length){
for(int i=0;i<arr2.length;i++){
arr2[i]=arr1[i];
}
}else{
for(int i=0;i<arr2.length;i++){
arr2[i]=arr1[i%(arr1.length)];
}
}
for(int i=0;i<arr2.length;i++){
System.out.print(arr2[i]+" ");
}
}
2、矩阵转置(二维数组)
public static void rever(int[][] arr) {
for (int i = 0; i < arr.length; i++) {
for (int j = 0; j < i; j++) {
int temp = arr[i][j];
arr[i][j] = arr[j][i];
arr[j][i] = temp;
}
}
}
public static void out(int[][] arr) {
for (int i = 0; i < arr.length; i++) {
for (int j = 0; j < arr[i].length; j++) {
System.out.print(arr[i][j] + " ");
}
System.out.println();
}
}
3、面向对象与面向过程
满汉全席的例子 对象:先找负责人 过程:自己全做一遍
面向过程强调功能行为 面向对象将功能封装进对象,强调具备了功能的对象
4、类和对象的关系
对象:是实实在在的个体 类:对现实事务的软件抽象
5、成员变量有默认初始化值 局部变量需手动初始化
day04
一、java -x 查看java非标准输出帮助
java -Xmx100m 设置jvm的堆空间最大值
-Xms100m 设置jvm的堆空间初始值
二、匿名对象 new Person().run();
作为参数进行传递 run
三、封装:隐藏对象的属性和实现细节,仅对外提供公共访问方式
1、子类会继承父类的所有东西,而修饰符只是影响属性或者方法对外是否可见。
2、子类不能继承父类的私有属性,但是如果子类中公有的方法影响到了父类私有属性,那么私有属性是能够被子类使用的
四、构造函数
1、函数名和类名形同
2、无返回值
3、可以重载
4、如果类没有定义构造函数,jvm分配一个空构造
5、创建对象
五、构造代码块 {}
从上到下按序执行
六、对象的创建过程
1、静态代码块:在类加载期间执行,且只执行一次
2、静态成员不可以访问非静态
3、静态成员变量通过类来访问
七、this和super
指向对象自身的引用,用于区分成员变量和方法的形参。
this()访问当前类的构造函数,且必须 在第一行,为了构造函数的重用
super()访问父类的构造函数
静态方法没有this与super
八:static
随着类加载而加载
优先于对象存在
被所有对象所共享
可以直接被类名调用
静态方法不可以写this,super
问:百钱买百鸡
公鸡:5/只 母鸡:3/只 小鸡1/3只 100元买100只
public class Buy {
//公鸡5yuan一只,母鸡3元一只,小鸡3只一元钱,100元买100只
public static void main(String[] args) {
for (int i = 0; i < 100 / 5; i++) {
for(int j=0;j<100/3;j++){
for(int k=0;k<100;k=k+3){
int count=i+j+k;
int money=i*5+j*3+(k/3);
if(money==100&&count==100){
System.out.println("公鸡:"+i+"母鸡:"+j+"小鸡"+k);
}
}
}
}
}
}
九、方法的重写与重载
重写(Override)存在于继承体系中,指子类实现了一个与父类在方法声明上完全相同的一个方法,子类的返回值类型要等于或者小于父类的返回值;
重载(Overload)存在于同一个类中,指一个方法与已经存在的方法名称上相同,但是参数类型、个数、顺序至少有一个不同。应该注意的是,返回值不同,其它都相同不算是重载
方法覆盖:1、静态覆盖静态。非静态覆盖非静态
2、非私有方法,才能重写
3、子类的访问权限要大于父类的方法访问权限
十、子类的实例化过程:
子类中所有的构造函数默认都会访问父类中空参数的构造函数,因为每一个构造函数的第一行都有一条默认的语句super();
十一、final
类 方法 变量
十二、内部类:
1、定义在类内部的类成为内部类
2、内部类可以在类成员位置上
3、内部类还可以在方法内定义
4、内部类访问局部变量时,不能局部变量进行重新赋值。java8不要求必须给局部变量使用final修饰
day04
一、抽象类
抽象方法:没有函数体的方法,必须使用abstract修饰,abstract void cry();必须在抽象类中
抽象类不能实例化
抽象类:1、可以有构造函数
2、由子类来实例化
二、非法修饰符组合: private+abstract fianl+abstract
三、接口interface :最低标准 usb例子
成员变量:public static final
成员函数:public void white();
特点:所有方法都是抽象的,用来多实现,功能扩展
面向接口编程:降低耦合度,可多重继承
四、多态:同一种事物表现出的多种形态
三个条件: 必须要有继承
必须要重写
父类引用指向子类对象
ClassCastException:类转换异常
类中方法可以覆盖,成员变量(资产)不能覆盖
五、匿名内部类:简化代码量,将类的声明,方法的实现,对象的创建一气呵成
public class 匿名内部类 {
public static void main(String[] args) {
tuHao t = new tuHao(new Bfm() {
@Override
public void white() {
System.out.println("white....");
}
});
}
}
interface Bfm {
void white();
}
class tuHao {
public tuHao(Bfm bfm) {
bfm.white();
}
}
六、适配器模式
接口适配器:有时我们写的一个接口中有多个抽象方法,当我们写该接口的实现类时,必须实现该接口的所有方法,
这明显有时比较浪费,因为并不是所有的方法都是我们需要的,有时只需要某一些,此处为了解决这个问题
我们引入了接口的适配器模式,借助于一个抽象类,该抽象类实现了该接口,
实现了所有的方法,而我们不和原始的接口打交道,只和该抽象类取得联系,所以我们写一个类,继承该抽象类,
重写我们需要的方法就行。
public class Adapter {
public static void main(String[] args) {
Button b1=new Button();
//匿名内部类对象
b1.addListener(new MouseAdapter() {
@Override
public void onClick() {
System.out.println("单机");
}
@Override
public void onDbClick() {
System.out.println("双击");
}
});
b1.click();
b1.onDbClick();
}
}
//按钮
class Button{
private MouseListener listener;
public void addListener(MouseListener listener){
this.listener=listener;
}
public void click(){
listener.onClick();
}
public void onDbClick(){
listener.onDbClick();
}
}
//鼠标监听器
interface MouseListener{
public void onClick();
public void onDbClick();
public void rightClick();
public void leftClick();
}
//鼠标适配器
abstract class MouseAdapter implements MouseListener{
public void rightClick(){ //可空实现
}
public void leftClick(){
}
}
day05
异常
一、
throw抛出异常对象的指令 throws在方法中修饰抛出异常的关键字
try-catch-finally
finally只有一种情况不会执行,就是sysyem.exit();
可以有多个catch语句,catch的顺序需要注意,子类异常需要先行catch,否则代码不可达,编译无法通过
方法重写时,不能声明抛出新的异常类型,只能是原有的异常体系。
二、java -cp classes -d xxx.java //-cp指定编译程序时需要搜索的类路径顺序
java -d classes xxx.java //-d
指定存放classes文件的位置,同时生成对应的目录树
三、包、权限
jar cvf xxx.jar -C foo/ . //将foo目录下的所有文件进行归档,生成xxx.jar
四、进程:1、运行时的应用程序
2、进程之间的内存不是共享(独占)
3、进程间通信使用套接字 socket
线程:1、进程内并发执行的代码段
2、线程之间共享内存
3、创建灵活响应的桌面程序
4、每个运行的线程对应一个stack
5、应用程序至少有一个线程(主线程)
五、创建线程的方式
栈溢出:死递归
1、Thread.yield() 让当前线程让出cpu抢占权,具有谦让之意,顺时的动作
2、Thread.sleep()让当前线程休眠指定毫秒数
3、Thred.join() 当前线程等待指定的线程结束后才能继续运行
4、Thread.setDaemon(true); 守护线程 为其他线程提供服务的线程
若进程中剩余线程都是守护线程的话,则进程终止了
线程间通信,产生共享资源的问题:加锁,防止并发访问。由并行变为串行
例子:在火车上上厕所,抢到之后马上上锁,出来后,其他线程继续抢;
synchronized
取票问题:
public class Ticket {
public static void main(String[] args) {
Saler s1 = new Saler("s1");
Saler s2 = new Saler("s2");
s1.start();
s2.start();
}
}
class Saler extends Thread {
static int tickets = 100;
static Object lock = new Object();
private String name;
public Saler(String name) {
this.name = name;
}
public void run() {
while (true) {
int t = getTickets();
if (t == -1) {
return;
} else {
System.out.println(name + ":" + t);
}
}
}
//取票
public int getTickets() {
synchronized (lock) {
int t = tickets;
tickets = tickets - 1;
return t < 1 ? -1 : t;
}
}
}
六、同步方法public synchronized void save(){}与同步代码块synchronized(object){}的区别?
同步代码块执行期间,线程始终持有对象的监控权,其他线程只能等待
七、同步静态方法 ,使用类作为同步标记
public staitc synchronized xxx(...){
}
八、生产者和消费者
public class ThreadDemo {
public static void main(String[] args) {
Pool pool = new Pool();
Productor p1 = new Productor("生產者", pool);
Productor p2 = new Productor("生產者", pool);
Customer c1 = new Customer("消費者", pool);
p1.start();
p2.start();
c1.start();
}
}
//生产者
class Productor extends Thread {
static int i = 0;
private String name;
private Pool pool;
public Productor(String name, Pool pool) {
this.name = name;
this.pool = pool;
}
public void run() {
while (true) {
pool.add(i++);
try {
Thread.sleep(100);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("生产了" + i + "");
}
}
}
//消费者
class Customer extends Thread {
private String name;
private Pool pool;
public Customer(String name, Pool pool) {
this.name = name;
this.pool = pool;
}
public void run() {
while (true) {
int i = pool.remove();
try {
Thread.sleep(100);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("消费了" + i);
}
}
}
//生产 删除方法类
class Pool {
private List<Integer> list = new ArrayList<Integer>();
//容量最大值
private int Max = 100;//防止栈溢出,到达100等待
//添加元素
public void add(int n) {
synchronized (this) {
try {
while (list.size() >= Max) {
this.wait(1);
}
list.add(n);
System.out.println("size =="+list.size());
this.notify();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
//刪除元素
public int remove() {
synchronized (this) {
try {
while (list.size() == 0) {
this.wait(1);
}
int i = list.remove(0);
this.notify();
return i;
} catch (Exception e) {
e.printStackTrace();
}
return -1;
}
}
}
需要注意的是:java.lang.IllegalMonitorStateException
wait和notify方法的调用必须处在对象的锁中,调用这些方法时首先需要获得该对象的锁
消费者被唤醒后是从wait()方法后面执行,而不是重新从同步块开始
九、wait()和sleep()的区别?
sleep() :释放cpu执行权,不释放锁
wait():让当前线程进入锁旗标的等待队列,释放cpu执行权,释放锁
暂定当前正在执行的线程,并释放资源锁,让其他线程可以有机会运行(程序停顿在这一行).
notify()
十、解决死锁的问题
notifyAll()通知所有线程可以抢占cpu和锁旗标监控权
wait(1000);等待固定的時間點
同步代码块和同步方法
day06
equals() 与 == 的区别
对于基本类型,== 判断两个值是否相等(内存地址),基本类型没有 equals() 方法。
对于引用类型,== 判断两个实例是否引用同一个对象,而 equals() 判断引用的对象(对象内容)是否等价。需重写。
一、Runnable接口
1、接口
2、public void runn(){};
3、使用Runnable对象创建线程(有3中创建方式)
new Thread(Runnable r).start();
4、供现有类实现线程功能
5、静态同步方法是使用class作为锁;
6、非静态同步方法是使用this(当前对象)作为锁;
public class Test {
public static void main(String[] args) {
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println(i);
}
}
}).start();
}
}
二、CAS:compare and set
避免同步带来的效率降低
三、线程安全问题
同步方法,同步代码块,静态同步代码块
四、线程的六种状态:
1.new 新建
2.runnable 可运行
3.blocked等待监视器的锁定权 synchronized(this) 阻塞
4.waiting 一个线程等待另一个线程特定的操作 wait();
5.timed waiting 限时等待 wait(参数);
6.terminated 死亡
7.sleep休眠
五、String
1、一旦初始化不可被改变
2、创建String的区别:
String s1="abc";//产生一个对象
String s2=new String("abc");//产生二个对象
3、String类的部分方法
例子:
public class ziFu {
public static void main(String[] args) {
String s1 = "abc defga";
String s2 = "gzzz";
System.out.println(s1.charAt(1));// 返回指定索引处的 char 值。 b
System.out.println(s1.contains(s2));//当且仅当此字符串包含 char 值的指定序列时,才返回 true。
System.out.println(s1.length());// 返回此字符串的长度。
System.out.println(s1.toCharArray()); //将此字符串转换为一个新的字符数组。
System.out.println(s1.indexOf("a"));//返回指定字符在此字符串中第一次出现处的索引
System.out.println(s1.endsWith(s2));// 测试此字符串是否以指定的后缀结束。
System.out.println(s1.getBytes());//将字符串转换成字节数组
System.out.println(s1.replace(s1,s2));//用s2替换s1
System.out.println(s1.toUpperCase());//变为大写 toLowerCase()小写
String [] s3=s1.split(" ");// 根据给定的正则表达式的匹配来拆分此字符串。
System.out.println(s3);
System.out.println(s1.substring(2));//截取
System.out.println(s1.substring(1,7));//截取左闭右开区间 bcdefg
}
}
4、debug
5、编码表:
ASCII:7位表示 GBK UniCode:国际标准码 2个字节 UTF-8:最多使用3个byte表示字符
小组合作开发先调字符集:Utf-8码
字符在内存中存储的都是unicode码
day07
作业:字符串反转
1、StringBuffer 的reverse方法
2、利用栈
3、递归
一、StringBuffer
1、字符串缓冲区
2、线程安全的
二、StringBuilder
1、字符串构建器
2、线程不安全
三、包装类wrapper
boolean —> Boolean
char —> Character
byte—> Byte
short—> Short
long—> Long
int —> Integer
float—> Float
double—> Double
四、建造器模式
五、自动拆箱与自动装箱
1、自动装箱:将基本类型自动装换成包装类对象
2、自动拆箱:将包装类对象自动装换成基本类型
Integer a=new Integer(12); //自动装箱 Integer a=12;
Integer b=new Integer(13);
a+b=a.intValue()+b.intValue();
六、基本类型与包装类的区别(int 与Integer的区别)
1、包装类是对象,拥有方法和字段;基本类型不是
2、包装类是引用传递,基本类型是值传递。
3、存储位置不同,基本类型在栈中,包装类型在堆中
4、声明方式不同,基本类型不需要new,包装类需要new在堆内存中,通过对象的引用来调用。
5、包装类可以声明为null,基本类型需初始化 Inteager a=null;
七、泛型
八、集合
数组:元素类型相同、长度固定、地址连续、下标访问以0为基址
集合:只能存放对象元素类型可以不同、长度可变
collection的两个接口:list接口:有序可重复 set接口:无序不重复 (TreeSet特殊有序)
ArrayList:数组 查找快 存储满
list add(..)
list.remove(index);
list.get(index);
list.clear();
LinkedList:链表 通过手拉手实现对象引用,存储快,查询慢
九、重写equals()
public voolean equals(Object obj){
//1、obj==null
if(obj==null){
return false;
}
//2、是否是同一对象
if(this==obj){
return true;
}
//3、判断obj是否是person实例
if(obj instanceof Person){
Person p0=(Pserson)obj;
if(this.name.equals(p0.name)&&this.age==p0.age){
return true;
}
}
return fasle;
}
}
十、迭代器
Iterator it=i.terator();
while(it.hasNext()){
System.out.println(it.next());
}
day08
一个中文占几个字节?(不同的编码格式下)
一、Map
1、map接口是单独的接口,没有继承任何接口,与之前的jdk版本不同
2、key-value对,称为Entry
3、map.size()是entry的数量
4、put放入,get提取
5、HashMap.hash()方法意义
6、Node<k,v>
class Node<k,v>{
final int hash; //进入数组位置的一种方式
final k key; //key不能修改
v value, //value
Node <k,v>next; //
}
7、元素重复的判断标准
(p.hash == hash &&((k = p.key) == key || (key != null && key.equals(k))))
8、(p.hash == hash &&((k = p.key) == key || (key != null && key.equals(k))))
a. new Hash不同,对象不同
b. new Hash相同。对象是同一对象,则对象相同
c. new Hash相同,对象不是同一对象,再判断equals方法,则对象相同性判定和equals一致
5、迭代entrySet keySet
//迭代Map entrySet
Set<Map.Entry<String, String>> entries = map.entrySet();
Iterator<Map.Entry<String, String>> iterator = entries.iterator();
while(iterator.hasNext()){
Map.Entry<String,String> entry = iterator.next();
String key=entry.getKey();
String value=entry.getValue();
System.out.println(key+"==="+value);
}
//增加for
Set<Map.Entry<Integer, String>> entries = map.entrySet(); //crtl+alt+v
for(Map.Entry<Integer,String> entry:entries){
Integer key=entry.getKey();
String value=entry.getValue();
System.out.println(key+"==="+value);
}
//迭代key keySet
Set<String> set = map.keySet();
Iterator<String> iterator = set.iterator();
while(iterator.hasNext()){
String key=iterator.next();
String value=map.get(key);
System.out.println(key+"=="+value);
}
//增加for
Set<Integer> keys = map.keySet();
for(Integer key:keys){
System.out.println(key+"==="+map.get(key));
}
//迭代value
Collection<String> values = map.values();
Iterator<String> iterator = values.iterator();
while(iterator.hasNext()){
String value = iterator.next();
System.out.println(value);
}
二、
问:
hashMap中的hash算法的实现原理,为什么?
1、为什么移位?高16位向右移动16位,由高低16位做异或运算:目的是哈希值跟特征值相关
2、为什么异或?相同为0,不同为1 使对象更加分散
hashMap扩容?bucket
三、唯一性
HashSet:通过hashMap实现的
TreeSet:通过compareTo或者compare方法,元素以二叉树的形式存放
四、集合的嵌套
public class Demo {
public static void main(String[] args) {
//班级人数5
List<String> names = null;
//年级:10个班级的集合
List<List<String>> grades = null;
// 学校:6个年级的集合
List<List<List<String>>> school = new ArrayList<List<List<String>>>();
for (int i = 1; i <= 6; i++) {
//创建每个年级,是班级的集合
grades = new ArrayList<List<String>>();
school.add(grades);
//处理每个年级的班级集合
for (int j = 1; j <= 10; j++) {
names = new ArrayList<String>();
grades.add(names);
for (int k = 1; k <= 5; k++) {
names.add("tom--" + i + "-" + j + "-" + k);
}
}
}
outName(school);
}
//迭代输出
public static void outName(List<List<List<String>>> allNames) {
Iterator<List<List<String>>> it = allNames.iterator();
//每个年级
while (it.hasNext()) {
List<List<String>> grade = it.next();
//班级
Iterator<List<String>> classes = grade.iterator();
while (classes.hasNext()) {
List<String> names = classes.next();
Iterator<String> nameIt = names.iterator();
while (nameIt.hasNext()) {
System.out.println(nameIt.next());
}
}
}
}
}
day09
一、Map与Collection在集合中并列存在
Map存储元素用put,Collection使用add方法
Map没有直接取出元素的方法,而是先转成Set集合,在通过迭代获取元素
Map集合中key要保持唯一性
二、HashMap与HashTable与TreeMap
三、集合工具类
Collection的max,min,synchronizedList,sort
Arrays的sort,asList,binarySearch
四、可变参数
public void add(String a,String...str) jdk1.5之后必须是方法的最后一个参数
五、数组的拷贝(扩容)
public class test1 {
public static void main(String[] args) {
int a1[]={1,2,3,4,5};
int a2[]=new int[10];
//public static native void arraycopy(Object src,int srcPos, Object dest, int destPos,int length);
// 原数组,原数组的开始位置,目标数组,目标数组的的开始位置,拷贝的个数
System.arraycopy(a1,1,a2,3,3);
System.out.println(Arrays.toString(a1)); //[1, 2, 3, 4, 5]
System.out.println(Arrays.toString(a2)); //[0, 0, 0, 2, 3, 4, 0, 0, 0, 0]
}
}
day10
一、IO流
流的类型
字符流:操作文本 Reader Writer
字节流:二进制文件 InputStream OutputStream 可操作媒体文件。字符串
流向
输入:读操作
输出:写操作
二、java.io.FileWriter
1、new FileWriter(String path);
2、write(String str);写入字符数据到流中
3、flush() 清理流
4、close()关闭 ,隐藏了flush()操作
5、流在close之后,不能再写入数据
可重复关闭,不会出现问题
读文件要比写文件复杂
public class Test {
public static void main(String[] args) {
try {
FileReader reader = new FileReader("d:/hello.txt");
char[] buffer = new char[3];
int length = -1;
while ((length = reader.read(buffer)) != -1) {
System.out.println(new String(buffer, 0, length));
}
reader.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
定义文件路径时,可以用"/"或者"\\"
作业:1、实现文件的复制
public class Test {
public static void main(String[] args) {
try {
FileInputStream fis = new FileInputStream("d:/hello.txt");
FileOutputStream fos = new FileOutputStream("H:/hello.txt");
byte[] buffer = new byte[1024];
int len = 0;
while ((len = fis.read(buffer)) != -1) {
fos.write(buffer, 0, len);
fos.flush();
}
fis.close();
fos.close();
System.out.println("over");
} catch (Exception e) {
e.printStackTrace();
}
}
}
2、文件的刪除
public class Test2 {
public static void main(String[] args) {
File dir=new File("d://liu");
deleteFile(dir);
}
private static void deleteFile(File dir) {
File[] files = dir.listFiles();//1,获取该文件夹下的所有的文件和文件夹
for (File file : files) {//2,遍历数组
if (file.isFile()) {//3,判断是文件直接删除
file.delete();
} else {
deleteFile(file); //4,如果是文件夹,递归调用
}
}
dir.delete();//5,循环结束后,把空文件夹删掉
System.out.println("删除完毕");
}
3、使用FileWriter,将1-100万写入到文本中
4、hashSet和hashMap的关系
5、文件切割与合成
三、装饰模式:顾名思义,就是对已经存在的某些类进行装饰,以此来扩展一些功能
Xxxx extends Yyyy{
private Yyyy yy;
public void zzz(){
...
yy.zzz();
...
}
}
字节流转换成字符流 InputSteamReader/outputStreamWriter
四、缓冲区字符流
1、BufferReader:这个类就是一个包装类,它可以包装字符流,将字符流放入缓存里,先把字符读到缓存里,到缓存满了或者你flush的时候,再读入内存,就是为了提供读的效率而设计的。
2、BufferWriter
BufferedInputStream和BufferedOutputStream这两个类分别是FilterInputStream和FilterOutputStream的子类,作为装饰器子类,使用它们可以防止每次读取/发送数据时进行实际的写操作,代表着使用缓冲区。
我们有必要知道不带缓冲的操作,每读一个字节就要写入一个字节,由于涉及磁盘的IO操作相比内存的操作要慢很多,所以不带缓冲的流效率很低。带缓冲的流,可以一次读很多字节,但不向磁盘中写入,只是先放到内存里。等凑够了缓冲区大小的时候一次性写入磁盘,这种方式可以减少磁盘操作次数,速度就会提高很多!
同时正因为它们实现了缓冲功能,所以要注意在使用BufferedOutputStream写完数据后,要调用flush()方法或close()方法,强行将缓冲区中的数据写出。否则可能无法写出数据。与之相似还BufferedReader和BufferedWriter两个类。
BufferedInputStream和BufferedOutputStream类就是实现了缓冲功能的输入流/输出流。使用带缓冲的输入输出流,效率更高,速度更快。
五、函数的回调
回调函数,通常是作为参数传递给调用者,调用者并不知道自己调用的到底是什么.另外有一点,回调函数大多用于多线程的情况
六、单元测试
@Test 要求:不能带参不能有返回值不能是静态方法
FileInputStream
支持skip()方法,skip向后跳的时候不能是文件头地址,可以超过文件末尾地址
FileOutputStream
不支持skip
RandomAccessFile
随机访问文件,定位到文件的任意位置
day11
问:1、IO流为什么读到-1
数组元素的类型是无符号字节类型(unsigned char),取值范围是0~255,-1到文件的末尾
在按字节读取文件内容时,会做一个位运算(与0xFF做与运算)使字节范围从-128到127变成0到255,然后就可以以-1为结束了。
2、 使用递归遍历指定目录的所有子目录,打印每个目录和文件的绝对路径。
public class Test {
public static void main(String[] args) {
countFile("d://qq");
}
public static void countFile(String path) {
File file = new File(path);
if (file.exists()) {
System.out.println(file.getAbsolutePath());
if (file.isDirectory()) {
File[] files = file.listFiles();
for (File f : files) {
String p = f.getAbsolutePath();
countFile(p);
}
}
}
}
}
day11
一、复制文件夹迭代文件:递归实现
public class Test {
public static void main(String[] args) {
copyDir(new File("D:\\要复制的文件"), new File("H:\\目标文件夹"));
System.out.println("over");
}
//拷贝目录
public static void copyDir(File src, File dest) {
if (src.exists()) {
//目录
if (src.isDirectory()) {
File dir = new File(dest, src.getName());
dir.mkdir();
File[] files = src.listFiles();
for (File f : files) {
copyDir(f, dir);
}
}
//文件
else {
//绝对路径
copyFile(src, dest);
}
}
}
//复制文件
public static void copyFile(File srcFile, File destDir) {
try {
if(!destDir.exists()){
destDir.mkdir();
}
//源文件
FileInputStream fis = new FileInputStream(srcFile);
//目标文件
File file = new File(destDir, srcFile.getName());
FileOutputStream fos = new FileOutputStream(file);
File[] files = srcFile.listFiles();
int len = -1;
byte[] buffer = new byte[100];
while ((len=fis.read(buffer)) != -1) {
fos.write(buffer, 0, len);
}
fis.close();
fos.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
二、RandomAccessFile
随机访问文件,支持随机读写
1、seek(int pos)
2、skipBytes(int num);
3、read();
4、write();
5、RandomAccesssFile(String str,String mode)
三、多线程复制文件
五、流的关闭
从外向里关
六、串行化 :
(序列化) 将java对象转换成某种格式的字节数组。
java.io.Serializable
1、可串行化接口
2、标识性接口
3、jvm
使用场景:1、把对象写到文件中去
2、深度复制
七、操作基本数据类型的流DataInputStream和DataOutputStream
操作字节数组类型的流ByteArrayInputStream和ByteArrayOutputStream
字符转换流:InputSreamReader和OutputSteamReader
FilterInputSream ObjectInputStream
八、Hash:
day12
GUI:图形用户接口
javax.Swing java.AWT
一、控件
二、布局管理器 LayOutManager
三、进程间通信:socket
ServerSocket 服务器端套接字
Socket 套接字
单工:有去无回,单向传输
半双工:不能同时进行收发
全双工:同时收发
四、TCP传输控制协议与UDP用户数据报协议
五、什么是深度复制和串行化?
把java对象转换成字节数组的过程叫串行化,由jvm完成。
基于串行化,我们可以实现深度复制,
六、串行化与反串行化是否经过构造函数?
没必要,串行化串行的是对象成员变量的值,跟方法没有关系。
day13
Rational Rose:用例图
类图
时序图
1、HashMap原理,内部数据结构?1.7与1.8的区别
JDK1.7中
使用一个Entry数组来存储数据,用key的hashcode取模来决定key会被放到数组里的位置,如果hashcode相同,或者hashcode取模后的结果相同(hash collision),那么这些key会被定位到Entry数组的同一个格子里,这些key会形成一个链表。
在hashcode特别差的情况下,比方说所有key的hashcode都相同,这个链表可能会很长,那么put/get操作都可能需要遍历这个链表
也就是说时间复杂度在最差情况下会退化到O(n)
JDK1.8中
使用一个Node数组来存储数据,但这个Node可能是链表结构,也可能是红黑树结构
如果插入的key的hashcode相同,那么这些key也会被定位到Node数组的同一个格子里。
如果同一个格子里的key不超过8个,使用链表结构存储。
如果超过了8个,那么会调用treeifyBin函数,将链表转换为红黑树。
那么即使hashcode完全相同,由于红黑树的特点,查找某个特定元素,也只需要O(log n)的开销
也就是说put/get的操作的时间复杂度最差只有O(log n)
2、HashMap中get,put方法过程?
3、HashMap中的Hash函数是怎么实现的?
4、HashMap怎么解决冲突,讲一下扩容过程,现在移动了新数组,位置肯定变了,那怎么定位到这个新数组中的位置?
5、concurrentHashMap是如何实现的?1.7与1.8的不同,为什么这么做?
6、HashMap的扩容怎么理解?
Node<k,v>
class Node<k,v>{
final int hash; //进入数组位置的一种方式
final k key; //key不能修改
v value, //value
Node <k,v>next; //
}
(1)resize() 初始化数组大小
(2)put怎么知道放在数组的哪一个位置
(1)先得到一个整形数值 key.hashCode() 高16位与低16位做异或运算 使结果分散
(2)范围控制在0-15之间 对%16取模
(3) tab[i=(n-1)&hash]) --n是10000
(4) key相同value相同 覆盖原数组
key相同value不同 形成链表 找到链表尾节点 尾插法
链表转红黑树 >8
红黑树存储
(5)数组长度不够怎么办? 16*0.75=12 大于12扩容 为什么是0.75?
if(++size>threshold){
resize();//扩容
}
数据移动: 一个数组 数组不为空,遍历数组
链表 if(hash&oldCap==0)
红黑树
5、concurrentHashMap
数组初始化:CAS无锁化,实现线程安全 只有一个线程去初始化only one
插入: 检查某个位置是否为空 为空插入 CAS
不为空 synchronized(当前数组下标,不会影响其他数组下标下面的锁机制) 代码块 降低锁密度
设计模式《Designer Pattern》
day14
一、基于Socket网络编程
//服务器端
public class ServerSocketDemo {
public static void main(String[] args) throws IOException {
ServerSocket ss=new ServerSocket(8888);
Socket s = ss.accept();
System.out.println("有人进来了");
InputStream is=s.getInputStream();
byte[] buffer=new byte[1024];
int len=-1;
while((len=is.read(buffer))!=-1){
System.out.println("收到消息:"+new String(buffer,0,len));
}
System.out.println("流关闭了");
is.close();
s.close();
ss.close();
}
}
/客户端
public class SocketDemo {
public static void main(String[] args) throws Exception {
Socket socket = new Socket("localhost", 8888);
OutputStream os = socket.getOutputStream();
//缓冲区阅读器
BufferedReader bis = new BufferedReader(new InputStreamReader(System.in));
while (true) {
String line = bis.readLine();
if (line != null & "exit".equals(line)) {
break;
}
if (line != null) {
os.write(line.getBytes());
}
}
os.close();
socket.close();
}
}
防止阻塞,需要多线程:支持多客户端的socket
二、开放系统互联参考模型OSI
Tcp三次握手:syn:同步信号
1、A发送同步信号x给B
2、B接受A的同步信号x,x+1,发送A+Y
Tcp/Ip:面向连接 安全 没容量限制
UDP:无连接 不安全 64k 如果传递大的文件怎么保证顺序性?制定报文?
Sender+receiver
DatagramSocket sock=new DatagramSocket(port);
DatagramPacket pack=new DatagramPacket();
pack.setAddress("x.x.x.255");
sock.send(DatagramPacket pack);
sock.receive(DatagramPacket pack);
协议://域名:port / path
netstat -ano
URL:统一资源定位符,是指向互联网的资源的一个指针 带层级结构/
URI: 统一资源标识符
day15
数据库
一、关系型数据库:结构化数据,行列
sc:service console 服务控制台程序,可以启动,停止,删除等服务
sc start MySQL
1、启动Mysql
mysql -u root -p root 链接loaclhost
mysql -h -u root -p root 连接远程服务器
2、查询当前日期与时间
select current_date; //伪劣
Select now(); //函数
3、显示所有数据库
--这是注释
show databases;
4、删除数据库
drop database 名称;
5、创建数据库
create database 名称;
6、使用指定的数据库
user 名称;
7、显示所有表
show tables;
8、创建表
create table 名称(id int,name varchar(20),age int);
9、查看表结构
describe 名称;
10、查询表数据
全表扫描
投影查询 select id,name,age from 名称;
11、插入数据
12、更新数据
update 名称 set age=22 where id=4;
12、删除记录
delete from 名称 where id =1;
查看表结构 desc 名称
二、jdbc
1、加载驱动 Class.forName("com.mysql.jdbc.Driver");
2、创建连接 url="jdbc:mysql://localhost:3306/数据库名"
3、创建Statement语句
4、调用Statement执行sql语句
ResultSet rs=statement.executeQuery(sql);
5、遍历ResultSet
while(rs.next()){
rs.getInt(1);
rs.getString("name");
}
三、mysql约束
primary key
null不能重复
自增
create table test(id int primary key auto_increment,name varchar(20) not null,age int);
带条件创建
crete database if not exists 数据库名;
create table if not exists 表名;
DESC降序 ASC升序
聚合查询
总数count(*) 最大max() 最小min() 平均avg() 求和sum()
分页查询
select * from test limit 1,3; 从第2条查,查3条
使用mysql命令执行sql脚本
source d:/java/findtest.sql
修改字段
alter table 表名 modify column id int primary key auto_increment;
addBatch()方法:增加批处理语句。
executeQuery()方法:运行查询语句,返回ReaultSet对象。
day15
一、
对表重命名 alter table 原名 rename 新名;
对表加一列 alter table 表名 add column 字段名 varchar(20);
Statement:存在sql注入问题 1 ' or 1=1-- 性能较差
prepareStatement 预处理语句 ?占位符
多次执行,绑定参数
防止sql注入问题
大量操作时,可以采用batch处理
CallableStatement对象用于执行对数据库已存储过程(函数)的调用;速度快
二、事务transaction
特性:ACID:Atomic Consistent Isolate Durable
commit rooback
在cli关闭mysql的自动提交 set autocommit=0;
事务的并发执行导致3个现象
脏读:读未提交
不可重复读:一个事物在进行相同条件的查询,连续的两次或两次以上,每次结果都不同 update
幻读:一个事物在进行相同条件的查询,连续的两次或两次以上,在稍后查询会发现一些原来没有的记录insert
隔离级别
1、 read uncommited
2、 read committed (oracle默认)
3、 repeatable read 可重复读(mysql默认1)
4、 Seriailizable 串行化
查看事务当前隔离级别: select @@session.tx_isolation; 当前会话
@@global.tx_isolation; 全局的
改变事务隔离级别:set (global /session)transaction isolation level read uncommitter;
三、存储过程 存放在数据库中的一组sql,在服务器端执行,没有返回值
1、创建存储过程
语法: DELIMITER //
CREATE PROCEDURE dorepeat(IN a INT,IN b INT,OUT c INT)
BEGIN
SET c:=a+b;
END
//
2、java程序中获取
public void add throws Exception(){
//输出的
String sql="{call add(?,?,?)}";
//创建callableStatement对象
CallableStatement cst=conn.prepareCall(sql);
//对于输入绑定参数
cst.setInt(1,1);
cst.setInt(2,2);
//注册输出参数
cst.registerOutParameter(3,Types.INTERGER);
//执行存储过程
cst.execute();
//取得输出参数
int count=cst.getInt(3);
System.out.println(count);
}
四、存储函数 :有返回值
DELIMITER //
create function add(a int,b int) returns int
return a+b //
作业: 创建1-100000存储过程
DELIMITER//
create procedure if exists sp_insert(in num int)
begin
declare i int default 0;
start transaction;
while i<num do
insert into persons(name,password,age) values(concat('tom',i),concat('',i),i%30);
set i=i+1;
end while;
commit;
end
//
day16
一、 mysql大字段处理
增加longblob字段
alter table test add column photo longblob;
alter table test add column memp longtext;
二、行级锁: 多个事务并发修改同一条记录
表级锁:性能较差 lock tables xxx write ,yyy read; 上锁
unlock tables ; 解锁
三、分组查询
group by
对分组之后的再进行过滤:having
四、连接查询
alter table orders add constraint foreign key(cid) references customers(id);
笛卡儿积:没有任何连接条件
select a.*,b.* from customers a,oreders b;1
等值连接查询
select a.*,b.* from customers a,orders b where a.id=b.cid;
使用join连接查询(内链接)
select a.id,a.name,b.id,b.orderno from customers a inner join orders b on a.id=b.cid;
外连接:可以补齐null数据
左外连接 select a.id,a.name,b.i,b.orderno,b.price from customers a left outer join orders b on a.id=b.cid;
右外连接 select a.id,a.name,b.i,b.orderno,b.price from customers a right outer join orders b on a.id=b.cid;
全连接
五、(集合查询)联合查询union(纵向合成若干查询的结果)
查询列数相同
select id,name from customers union select id,orderno from orders;
union all 包含重复数据
minus 减法 不支持
intersect 交集 不支持
distince去重复 ,放在sql前 select distinct age from customers;
select count(distinct age) as ages form cutomers;
六、范围运算
and or
bewteen...and... select * from customers where id between 4 and 8;
in select * from customers where id in(1,2,3,4);
any select * from orders where cid>any(select id from customers like 't%');
all select * from orders where cid>all(select id from customers like 't%');
池化模式:使用有限的对象数量服务于大量的客户端请求(超市的收银窗口)
作业:会使用c3p0
阐述连接池原理
面试题:
Mysql索引实现原理?
Mysisam与InnoDb引擎中B+树的区别?
MySql主从复制会引发什么问题?
垂直拆分与水平拆分
垂直拆分:分为订单,支付,消息数据库...
水平拆分:user user1 user2 user3...
为什么分表分库提高查询效率:使用第三方数据库中间件mycat 或者shardingjdbc实现联合查询
day17
一、反射 私有成员也能访问,破坏规则
1、动态访问对象的属性和方法
2、常用类
CLass Class.forName();方法区
Constructor 构造函数 setAccessibale(true);可见性
Method
Field
二、类加载器:抽象类
三、动态代理:不改变源码,增加新的功能
四、JVM jvisualvm查看jvm结构
堆:被所有线程共享
年轻代: eden区:所有对象在此创建
survivor-1
survivor-2
年老代:
永久代:在方法区
栈: 每个线程对应自己的栈空间,线程栈=方法栈 oom栈溢出
方法区:共享
本地方法区:知识执行本地方法时使用的
程序计数器:
什么时候出现栈溢出?
五、GC
System.gc();显示回收
finalize():
jconsole 打开java控制台 看类加载过程'
六、NIO:完成高速IO,而无需编写自定义本地代码 非阻塞 一个线程通过轮询的方式
IO基于流技术,按照字节处理
Nio基于块,使用分块方式处理,编程不易
Channel 打开的连接
------
channel和Buffer是nio的核心对象
与stream类似,数据通过通道传输
实现:
FileChannel SocketChannel DatagramChannel
Buffer
-------
是容器对象的核心
从channel中读取的数据进入到buffer中
NIO必须通过buffer完成数据读写,跟踪读写过程
ByteBuffer
capactiry 容量
limit 限制 第一个不能读写的元素索引
position 当前指针的位置 ,读写下一个元素的索引
mark 标记 默认值-1
remain=limit-position 剩余的空间
0<mark<position<limit<capacity
ByteBuffer.allocate(size); //堆内存缓冲区 jvm head
ByteBuffer.allocateDirect(size); //直接内存缓冲区 off-head离堆 Cleaner.clean();
//堆缓冲区
HeadByteBuffer buffer=ByteBuffer.allocate(1024);
MemoryMapper 文件内存映射
RandomAccessFile faf=new RandomAccessFile("d:/koala2.jpg","rw");
FileInputStream fis=null;
FileChannel fc;
MappedByteBuffer buffer=fc.map(MapMode.READ_ONLY,0,raf.length());
int cap=buffer.capacity();
Sout(cap);
FilfChannel fout=new RandomAccessFile("d:/koala2.jpg","rw").getChannel();
fout.write(buffer);
fout.close();
SocketChannel
1、ServerSocketChannel
服务器套接字通道
2、SocketChannel
客户端套接字通道
3、SocketChannel.finishConnection()
处理连接完成工作
如果连接完成,立即返回true,
如果通道是非阻塞的,如果连接还未完成,则返回false.
4、selector 选择器
Selector selector=Selector.open();
内部维护了3个集合
keySet 所有通道注册时产生的key
Selected-key set
cancalled-key set
//服务端
ServerSocketChannel ssc=new ServerSocketChannel.open();
SocketAddress addr=new InetSocketAddress("localhost",8888);//创建绑定地址
ssc.bing(addr);//进行绑定
ssc.configureBlocking(false);//配置非阻塞模式
while(true){
SocketChannel sc=ssc.accept();
sout("over: "+sc);
Thread.sleep(2000);
}
//客户端
SocketChannel sc=SocketChannel.open();
InetSocketAddress addr=new InetSocketAddress("localhost",8888);
sc.configureBlocking(flase);
boolean b=sc.connect(addr);
sc.finishConnect();
sout("client: "+sc);
面向接口/抽象类编程
//服务端
Selector selector=Selector.open();
ServerSocketChannel ssc=new ServerSocketChannel.open();
SocketAddress addr=new InetSocketAddress("localhost",8888);//创建绑定地址
ssc.bing(addr);//进行绑定
ssc.configureBlocking(false);//配置非阻塞模式
ssc.register(selector,SelectionKey.OP_ACCEPT);//在挑选器中注册ssc.指定SelectionKey.OP_ACCEPT
while(true){
selector.select();//开始挑选是阻塞的,至少一个被挑选出来
Set<SelectionKey> selkeys=selector.selectKeys();
Iterator<SelectionKey> it=selkeys.iterator();
while(it.hasNext()){
SelectionKey key= it.next();
if(key.isAcceptable()){
ServerSocketChannel ch= (ServerSocketChannel)key.channel();
SocketChannel sch=ch.accept();//接收连接
sch.register(selector,SelectionKey.OP.CONNECT|SelectionKey.OP_READ|SelectionKey.OP_WRITE);
}
sout(key);
it.remove();
}
}