`
lvwenwen
  • 浏览: 932037 次
  • 性别: Icon_minigender_1
  • 来自: 魔都
社区版块
存档分类
最新评论

java基础(毕向东)

阅读更多
Io (Input,output)流
1.Io流用来处理设备之间的数据传输,java对数据的传输是通过流的方式,java用于操作流的对象在Io包中,按流操作数据分为两种:字节流,字符流
按流的流向:输入流,输出流
如果是音频文件、图片、歌曲,就用字节流好点,如果是关系到中文(文本)的,用字符流好点.
字节流可用于任何类型的对象,包括二进制对象,而字符流只能处理字符或者字符串;
2. 字节流提供了处理任何类型的IO操作的功能,但它不能直接处理Unicode字符,而字符流就可以。

Io流基类:
1.字节流的抽象基类:
InputStream,OutputStream 子类FileInputStream
字符流的基类:
Reader,Writer   子类FileReader

处理文本文件用字符流 FileReader, FileWriter
图片属于二进制数据用 InputStream ,OutputStream

装饰模式: bufferReader(增强,可以一次读一行) fileReader(一次读一个)
装饰设计模式:当想要对已有的对象进行功能增强时,
可以定义类,将已有对象传入,基于已有的对象,并提供加强功能
那么自定义的该类成为装饰类
装饰设计模式:
当想要对已有的对象进行功能增强时,
可以定义类,将已有对象传入,基于已有的功能,并提供加强功能。
那么自定义的该类称为装饰类。


装饰与继承的区别:
装饰模式比继承要灵活。避免了继承体系臃肿。
而且降低了类于类之间的关系。

多态::“一个接口,多种实现”,就是同一种事物表现出的多种形态。

有Stream 的是字节流

二进制转十进制

InputStreamReader 将字节流转换为字符流
OutputStreamWriter 将字符流转换为字节流

内部类可以访问外部类的对象

线程互斥一定是同一个对象

外部类怎样调用类部类的方法

AtomicInteger


任何线程死了,怎样再启动


ReadWriteLock  ReentrantReadWriteLock

Condition

线程的同步,安全,什么时候用线程异步


MyReader//专门用于读取数据的类。
|--MyTextReader
|--MyBufferTextReader
|--MyMediaReader
|--MyBufferMediaReader
|--MyDataReader
|--MyBufferDataReader

class MyBufferReader
{
MyBufferReader(MyTextReader text)
{}
MyBufferReader(MyMediaReader media)
{}
}
上面这个类扩展性很差。
找到其参数的共同类型。通过多态的形式。可以提高扩展性。

class MyBufferReader extends MyReader
{
private MyReader r;
MyBufferReader(MyReader r)
{}
}

MyReader//专门用于读取数据的类。
|--MyTextReader
|--MyMediaReader
|--MyDataReader
|--MyBufferReader


以前是通过继承将每一个子类都具备缓冲功能。
那么继承体系会复杂,并不利于扩展。

现在优化思想。单独描述一下缓冲内容。
将需要被缓冲的对象。传递进来。也就是,谁需要被缓冲,谁就作为参数传递给缓冲区。
这样继承体系就变得很简单。优化了体系结构。

装饰模式比继承要灵活。避免了继承体系臃肿。
而且降低了类于类之间的关系。

装饰类因为增强已有对象,具备的功能和已有的是相同的,只不过提供了更强功能。
所以装饰类和被装饰类通常是都属于一个体系中的。


装饰类通常会通过构造方法接收被装饰的对象。
并基于被装饰的对象的功能,提供更强的功能。
装饰与继承的区别:
装饰模式比继承要灵活。避免了继承体系臃肿。
而且降低了类于类之间的关系。

有Stream 的是字节流
二进制转十进制
InputStreamReader 将字节流转换为字符流
OutputStreamWriter 将字符流转换为字节流

字符流和字节流:
字节流两个基类:
InputStream   OutputStream
FileWriter fw = new FileWriter("c:\\demo.txt");
//刷新流对象中的缓冲中的数据。
//将数据刷到目的地中。
//fw.flush();
//关闭流资源,但是关闭之前会刷新一次内部的缓冲中的数据。
//将数据刷到目的地中。
//和flush区别:flush刷新后,流可以继续使用,close刷新后,会将流关闭。
字符流两个基类:
Reader Writer

//字符流的操作
public static void copy_2()
{
FileWriter fw = null;
FileReader fr = null;
try
{
fw = new FileWriter("c:\\SystemDemo_copy.txt");
fr = new FileReader("c:\\SystemDemo.java");

char[] buf = new char[1024];

int len = 0;
while((len=fr.read(buf))!=-1)
{
fw.write(buf,0,len);
}
}
catch (IOException e)
{
throw new RuntimeException("读写失败");

}
finally
{
if(fr!=null)
try
{
fr.close();
}
catch (IOException e)
{
}
if(fw!=null)
try
{
fw.close();
}
catch (IOException e)
{
}
}
}

递归要注意:
1,限定条件。
2,要注意递归的次数。尽量避免内存溢出。

递归例题:
public static void showDir(File dir,int level)
{

System.out.println(getLevel(level)+dir.getName());

level++;
File[] files = dir.listFiles();
for(int x=0; x<files.length x if showdir else system.out.println public static int getsum n return string str="new" class test13 void main args stringbuilder sb="new" arr="{2,4,1,4,3,2,4,3,2,4};" count="0;" maxcount="1;" for y="x+1;">maxcount)
{
sb.delete(0,sb.length());
sb.append(arr[x]+" ");
maxcount = count;
}
else if(count==maxcount)
{
sb.append(arr[x]+" ");
}

count = 0;
}

System.out.println(sb);

}
}

在流操作规律讲解时:

源设备,
键盘 System.in,硬盘 FileStream,内存 ArrayStream。
目的设备:
控制台 System.out,硬盘FileStream,内存 ArrayStream。

编码:字符串变成字节数组。
解码:字节数组变成字符串。
String-->byte[];  str.getBytes(charsetName);
byte[] -->String: new String(byte[],charsetName);

用流的读写思想来操作数据。

流应用的小结:
1.流是用来处理数据的
2.处理数据时,一定要明确数据源,与数据目的地


流操作的基本规律:
最痛苦的就是流对象有很多,不知道该用哪一个。

通过三个明确来完成。

1,明确源和目的。
源:输入流。InputStream  Reader
目的:输出流。OutputStream  Writer。
2,操作的数据是否是纯文本。
是:字符流。
不是:字节流。

3,当体系明确后,在明确要使用哪个具体的对象。
通过设备来进行区分:
源设备:内存,硬盘。键盘
目的设备:内存,硬盘,控制台。


1,将一个文本文件中数据存储到另一个文件中。复制文件。
源:因为是源,所以使用读取流。InputStream Reader
是不是操作文本文件。
是!这时就可以选择Reader
这样体系就明确了。

接下来明确要使用该体系中的哪个对象。
明确设备:硬盘。上一个文件。
Reader体系中可以操作文件的对象是 FileReader

是否需要提高效率:是!。加入Reader体系中缓冲区 BufferedReader.


FileReader fr = new FileReader("a.txt");
BufferedReader bufr = new BufferedReader(fr);




目的:OutputStream Writer
是否是纯文本。
是!Writer。
设备:硬盘,一个文件。
Writer体系中可以操作文件的对象FileWriter。
是否需要提高效率:是!。加入Writer体系中缓冲区 BufferedWriter

FileWriter fw = new FileWriter("b.txt");
BufferedWriter bufw = new BufferedWriter(fw);


**************
扩展一下,想要把录入的数据按照指定的编码表(utf-8),将数据存到文件中。

目的:OutputStream  Writer
是否是存文本?是!Writer。
设备:硬盘。一个文件。使用 FileWriter。
但是FileWriter是使用的默认编码表。GBK.

但是存储时,需要加入指定编码表utf-8。而指定的编码表只有转换流可以指定。
所以要使用的对象是OutputStreamWriter。
而该转换流对象要接收一个字节输出流。而且还可以操作的文件的字节输出流。FileOutputStream,FileInputStream(两个转换流)
要下载图片,文本时一般要用到转换流(FileInputStream,FileOutputStream)

OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("d.txt"),"UTF-8");

需要高效吗?需要。
BufferedWriter bufw = new BufferedWriter(osw);

所以,记住。转换流什么使用。字符和字节之间的桥梁,通常,涉及到字符编码转换时,
需要用到转换流。

-----------------------------------网络编程--------------------------------------------
1.网络模型:osi参考模型,Tcp/Ip参考模型
2.网络通讯要素:1.Ip地址,端口号,传输协议(常用协议,TCP,UDP)
UDP:
1.将数据与源的目的封装在数据包中,不需要建立连接
2.每个数据包的大小限制在64k内
3.不需要建立连接,速度快
4.因无连接,是不可靠协议
TCP:
1.建立连接形成传输数据的通道
2.在连接中进行大数据传输
3.通过三次完成连接,是可靠协议
4.必须建立连接,效率低

(1).Socket:
1.Socket是为网络服务的一种机制
2.通信的两端都有Socket
3.网络通信就是Socket通信
4.数据在两个Socket间通过IO传输

(2)UDP传输
1.DatagramSocket与DatagramPacket
2.建立发送端,接受端
3建立数据包
4.调用Socket的发送接受方法
5.关闭Socket
在发送端,要在数据包对象中明确目的地 IP及端口。
DatagramSocket ds = new DatagramSocket();
byte[] by = “hello,udp”.getBytes();
DatagramPacket dp = new DatagramPacket(by,0,by.length,
InetAddress.getByName(“127.0.0.1”),10000);
ds.send(dp);
ds.close();
在接收端,要指定监听的端口。
DatagramSocket ds = new DatagramSocket(10000);
byte[] by = new byte[1024];
DatagramPacket dp = new DatagramPacket(by,by.length);
ds.receive(dp);
String str = new String(dp.getData(),0,dp.getLength());
System.out.println(str+"--"+dp.getAddress());
ds.close();
TCP传输
1.
Socket和ServerSocket
2.
建立客户端和服务器端
3.
建立连接后,通过Socket中的IO流进行数 据的传输
4.
关闭socket
基本思路(客户端)
1.
客户端需要明确服务器的ip地址以及端口,这样才 可以去试着建立连接,如果连接失败,会出现异 常。
2.
连接成功,说明客户端与服务端建立了通道,那么 通过IO流就可以进行数据的传输,而Socket对象已 经提供了输入流和输出流对象,通过 getInputStream(),getOutputStream()获取即可。
3.
与服务端通讯结束后,关闭Socket。
基本思路(服务端)
1.
服务端需要明确它要处理的数据是从哪个 端口进入的。
2.
当有客户端访问时,要明确是哪个客户 端,可通过accept()获取已连接的客户端 对象,并通过该对象与客户端通过IO流进 行数据传输。
3.
当该客户端访问结束,关闭该客户端。
客户端
1.
通过Socket建立对象并指定要连接的服务 端主机以及端口。
Socket s = new Socket(“192.168.1.1”,9999);
OutputStream out = s.getOutputStream();
out.write(“hello”.getBytes());
s.close();
服务端
?
建立服务端需要监听一个端口
ServerSocket ss = new ServerSocket(9999);
Socket s = ss.accept ();
InputStream in = s.getInputStream();
byte[] buf = new byte[1024];
int num = in.read(buf);
String str = new String(buf,0,num);
System.out.println(s.getInetAddress().toString()+”:”+str);
s.close();
ss.close();

Tcp传输最容易出现的问题
1.
客户端连接上服务端,两端都在等待,没 有任何数据传输。
2.
通过例程分析:
3.
因为read方法或者readLine方法是阻塞式。
4.
解决办法:
自定义结束标记
使用shutdownInput,shutdownOutput方法。
package cn.itcast.day23;
1.(网络编程Socket)综合例题:
/*
编写一个聊天程序。
有收数据的部分,和发数据的部分。
这两部分需要同时执行。
那就需要用到多线程技术。
一个线程控制收,一个线程控制发。

因为收和发动作是不一致的,所以要定义两个run方法。
而且这两个方法要封装到不同的类中。

*/
import java.io.*;
import java.net.*;
class Send implements Runnable
{
private DatagramSocket ds;
public Send(DatagramSocket ds)
{
this.ds = ds;
}


public void run()
{
try
{
BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));

String line = null;

while((line=bufr.readLine())!=null)
{

byte[] buf = line.getBytes();

DatagramPacket dp =
new DatagramPacket(buf,buf.length,InetAddress.getByName("192.168.1.255"),10002);

ds.send(dp);

if("886".equals(line))
break;
}
}
catch (Exception e)
{
throw new RuntimeException("发送端失败");
}
}
}

class Rece implements Runnable
{

private DatagramSocket ds;
public Rece(DatagramSocket ds)
{
this.ds = ds;
}
public void run()
{
try
{
while(true)
{
byte[] buf = new byte[1024];
DatagramPacket dp = new DatagramPacket(buf,buf.length);

ds.receive(dp);


String ip = dp.getAddress().getHostAddress();

String data = new String(dp.getData(),0,dp.getLength());

if("886".equals(data))
{
System.out.println(ip+"....离开聊天室");
break;
}


System.out.println(ip+":"+data);
}
}
catch (Exception e)
{
throw new RuntimeException("接收端失败");
}
}
}


class  ChatDemo
{
public static void main(String[] args) throws Exception
{
DatagramSocket sendSocket = new DatagramSocket();
DatagramSocket receSocket = new DatagramSocket(10002);

new Thread(new Send(sendSocket)).start();
new Thread(new Rece(receSocket)).start();

}
}


/*====第十三题==================================
找出一个整数数组{2,4,1,4,3,2,4,3,2}出现次数最多的数。
*/

class  Test13
{
public static void main(String[] args)
{
StringBuilder sb = new StringBuilder();

int[] arr = {2,4,4,4,3,2,4,3,3,4};
int count = 0;
int maxcount = 1;

for(int x=0; x<arr.length x for y="x+1;" if count>maxcount)
{
sb.delete(0,sb.length());
sb.append(arr[x]+" ");
maxcount = count;
}
else if(count==maxcount)
{
sb.append(arr[x]+" ");
}

count = 0;
}

System.out.println(sb);

}
}


/*====第十六题==================================
已知文件a.txt文件中的内容为“bcdeadferwplkou”,
请编写程序读取该文件内容,并按照自然顺序排序后输出到b.txt文件中。
即b.txt中的文件内容应为“abcd…………..”这样的顺序。
*/
import java.io.*;
import java.util.*;
class  Test16
{
public static void main(String[] args) throws Exception
{
/*
BufferedReader bufr = new BufferedReader(new FileReader("a.txt"));

String line = bufr.readLine();

char[] arr = line.toCharArray();

Arrays.sort(arr);

BufferedWriter bufw = new BufferedWriter(new FileWriter("b.txt"));

bufw.write(arr);

bufw.close();
bufr.close();
*/

writeFile();
}

public static void writeFile()throws Exception
{
FileReader fr = new FileReader("a.txt");

CharArrayWriter chw = new CharArrayWriter();

int ch = 0;

while((ch=fr.read())!=-1)
{
if(ch=='\r' || ch=='\n')
continue;
chw.write(ch);
}

char[] arr = chw.toCharArray();

Arrays.sort(arr);

FileWriter fw = new FileWriter("b.txt");

fw.write(arr);

fw.close();
fw.close();


}
}

package cn.itcast.day24;

/*====第十八题==================================
在java中,字符串“abcd”与字符串“ab你好”的长度是一样,都是四个字符。
但对应的字节数不同,一个汉字占两个字节。
定义一个方法,按照最大的字节数来取子串。
如:对于“ab你好”,如果取三个字节,那么子串就是ab与“你”字的半个,
那么半个就要舍弃。如果去四个字节就是“ab你”,取五个字节还是“ab你”.


思路:
汉字的默认编码gbk。
所以一个汉字两个字节。都是负数。
只有判断最后一个字节是否是负数。
如果是,就往前继续看有多少负数。如果是偶数个,不舍弃。
如果是奇数个,即舍弃最后一个字节。


步骤:
1,将字符串变成字节数组。
2,定义计数器,记录负数的个数。
3,在通过计数器的奇偶来判断是否舍弃。

*/

class  Test18
{
public static void main(String[] args)
{
String s = cutString("abc你好kk谢谢",7);
System.out.println(s);
}
public static String cutString(String str,int len)
{
byte[] arr = str.getBytes();
int count = 0;
for(int x = len-1; x>=0; x--)
{
if(arr[x]</arr.length></files.length>


JNI是java和本地应用程序之间的中介,调用用其他语言编写的程序。
  先编写java Hello.java程序,然后编译成class文件,再创建.h文件:javah -jni Hello ,再写一个本地实现,再创建一个共享的库

静态语句块 static {  } 当类加载时执行

finalize()protected,自动调用,内存不够的时候才调用,
System中gc() 静态的,显示垃圾回收。

子类和实现类中方法的访问权限不能低于父类和接口中的权限。

java中不允许类的多继承 单允许接口的多继承。extends A,B,C...........extends再implements前面

内部类(内置类):在类中定义一个类,仍是独立的类,可以访问外部类的私有成员变量Outer.this.
                   可以放在方法中也可以放在语句块中,当放在方法中,若在内部类中访问方法的变                   量或参数时,编译会报错,应把方法变量声明为final,内部类的访问修饰符和方法一                 样
StringBuffer    .delete(4,8)包括4不包括8, .insert(index,str) .reverse()反序

   基本数据类型传递的是数据的拷贝,引用类型传递的是引用的拷贝。为了不改变原始的对象数据,可以获取对象的一份拷贝,用Object中的clone()方法返回Object类型。子类重写clone()方法,为public,要super.clone(),可能抛出异常:CloneNotSupportedException,必须实现Cloneable接口,该接口中没有任何抽象方法,叫做标识接口。


    当调用println() 打印一个对象的时候默认调用了object中的toString()方法,建议每个子类重写toString()方法,object中的toString()方法返回string equal to:getClass().getName()+'@'+Integer.toHexString(hashCode())

数组的相关操作:
    数组的复制:System.arraycopy(Object src,int srcPos,Object dest,int destPos,int length)
    数组的排序:Arrays.sort() 返回类型void。当对 对象类型数组排序时,在数组中的所有对象必须
    实现Comparable接口,必须实现方法int compareTo(Object o),大于o返回正数,==返回0,else 负数
   有序元素查找:Arrays.binarySearch(a,value) 返回value在数组a中的index

封装类:java.long包中定义的。
Class类:java.long.Class
       getClass()获取Class实例,Class.forName(String name),会抛出异常:                    ClassNotFoundException, .class  .TYPE(基本类型的封装类)。

java 提供了对多线程程序的支持,实现多线程程序的两种方式:
(1)从Thread类继承:java.long包中,Thread.currentThread().getName():获取线程名。线程启动:
    void start(),然后会执行线程中的 void run()方法,可以理解为线程的入口。setDaemon(boolean)
    必须在start()前调用,设置为后台线程。静态的yield():放弃自己执行的权利,及暂停自己。
getPriority(),setPriority()获取设置优先级Thread.MAX_PRIORITY,MIN_PRIORITY,DEFAULT_PRIORITY
在java中,线程通常是抢占式的而不需要时间片分配。
(2)实现Runnable接口:只有一个方法void run()。  new Thread(st).start()。  
     Thread.sleep(long mills) 抛出异常:
     线程的同步方式:同步块和同步方法:
           同步块:synchronized(Object obj){}
           同步方法:public synchronized void sell(){}

ArrayList: 能自动增加容量的数组,toArrary()返回一个数组Object,ArrayList a=new ArrayList();
          a.add(" ");a.size();a.get(index);
           Arrays.asList()返回一个列表,是固定大小的列表,但可以更改元素:set(index,element)
迭代器(Iterator):访问集合中的元素,提供三个方法: iterator()返回迭代器
                   boolean hasNext()
                   Object next()
                   void remove() 删除上一个返回的元素, 列表不支持remove()
迭代器与for循环:如果未提供get()方法,for循环无法遍历元素,iterator可以,用集合类的对象就可                 获得迭代器,这样很通用。

Collections类:不是collection接口。全是静态方法
               排序:Collections.sort(),自然排序,升序,实现比较器Comparator接口:
                实现Comparable接口,必须实现方法int compareTo(Object o)
               获取最大最小元素:Collections.max(),Collection.min()
               在已排序的List中搜索指定元素:Collections.binarySearch()

LinkedList: 采用双向循环链表实现的。利用LinkedList实现栈(stack),队列(queue),
            双向队列(double-ended quequ)。
         栈: LinkedList li = new LinkedList();li.addFist();li.getFirst();li.removeFirst()
            li.isEmpty();
      队列:LinkedList li = new LinkedList();li.addLast();li.getLast();

ArrayList和LinkedList比较:ArrayList底层采用数组完成,而LinkedList用双向链表完成,除了数据本                            身还有两个引用,指向前一个和后一个元素。
                        如果经常在List中进行插入删除操作,用LinkedList, 随机访问ArrayList

HashSet:实现Set接口的hash table散列表:(哈希表),依靠HashMap实现,不能重复。无get()函数
        HashSet hs =new HashSet();hs.add();
        我们用该为要存放到散列表的各个对象定义hashCode()和equals()方法
TreeSet: 有序集合,缺省按升序排列;实现Comparable接口;TreeSet ts=new TreeSet();ts.add();
         没有get()方法,用iterator遍历
    HashSet是基于Hash算法实现的,性能优于TreeSet,通常使用HashSet,需要排序时用TreeSet。
  
HashMap:实现Map接口;与Collection无关,无add();HashMap hm=new HashMap();
         hm.put(key,value);有get(key)方法;Set keySet()返回key视图;Collection values()
         返回values视图: Set keys=hm.keySet;Collection values=hm.values();
         Set entry=hm.entrySet();返回key-values

TreeMap:按照key进行排序,和HashMap用法类似。HashMap的速度通常比TreeMap快,需要排序用TreeMap

HashMap   : JDK 1.2 之后的新类,异步处理方式,性能较高,属于非线程安全,允许设置Null
HashTable : JDK 1.0 时推出,同步处理方式,性能较低,属于线程安全,不允许设置Null

sleep()与wait()区别:
       sleep()是Therad中定义的方法,线程的睡眠,自动唤醒
       wait()是Object中定义的方法,用notify()或notifyAll()唤醒

单例模式singleton:构造函数私有化,在类内部创建私有实例,提供供外部访问的静态方法

抽象类不能new自己

串行化(Serialization)是计算机科学中的一个概念,它是指将对象存储到介质(如文件、内存缓冲区等)中或是以二进制方式通过网络传输。之后可以通过反串行化从这些连续的字节(byte)数据重新构建一个与原始对象状态相同的对象,因此在特定情况下也可以说是得到一个副本,但并不是所有情况都这样。
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics