javaSe,
javaSe,
javaSe
一、基础语法
1、数据类型
boolean、char
byte、short、int、long
float、double
基本类型:基本类型已经固定了大小,所以可以置于堆栈中,而且堆栈速度很快,也使得我们使用基本类型更高效的存储。而且因为具体的值直接存储在堆栈中,所以可以直接取得存储的值。
对象:使用new创建对象,将对象置于堆中,使用时需要先得到那个句柄,然后通过句柄的值获得那个对象。
因此使用了基本类型,不需要用new创建对象,而是创建一个并非句柄的自动变量,这个变量容纳了具体的值,并置于堆栈中,能够更高效的存储。相比而言,方便很多,也更快速、更高效。
2、运算符
1)赋值运算符
对于基本数据类型的赋值,是直接将一个值赋值到另一个地方,而对于对象赋值时,实际上操作的是它的句柄。
在我理解就是指向实际对象存储位置的一个地址值,也可以说是那个对象名,它的值就是那个地址值,也就是句柄。
2)算数运算符
+、-、*、/、%
++、--
3)关系运算符
<、>、=、>=、<=、==、!= 生成的是一个布尔值
对象比较:==、!=比较的是句柄,所以尽管对象的内容相同,句柄也有可能是不同的。若想比较两个对象的实际内容是否相同,就要使用equals(),但是这个方法不适用与主类型,那些类型直接使用==、!=即可。
4)逻辑运算符
开发中常用&&、||、!
& | 与 |
---|---|
| | 或 |
^ | 位异或 特点:一个数据对另一个数据位异或两次,该数本身不变。 |
~ | 按位取反 |
&&和&的区别?||和|同理
A:最终结果一样
B:&&具有短路效果。左边是false时,右边不执行。
5)移位运算符
<<(左移位运算符)、>>(右移位运算符)
int a=3>>2;
System.out.println(a);//11 00
int a=3<<2;
System.out.println(a);//11 1100=12
对于-1:
移位前:
1000 0001
1111 1110
1111 1111
负数对补码进行操作,补码等于反码+1
移位后:
1111 1100
1111 1011
1000 0100
-4
int a=-1<<2;
System.out.println(a);
结果:
0
12
-4
6)三元运算符
布尔表达式?值0:值1
若布尔表达式的结果为true,就计算值0,而且它的结果成为最终由运算符产生的值,否则就计算值1。
7)字串运算符+
str1+str2;//用于字符串的连接。
3、程序流程
1)单分支
if(...){
...
}
2)双分支
if(...){
...
}else{
...
}
3)多分支
if(...){
...
}else if(...){
...
}else if(...){
...
}else{
...
}
4)多分支(另一种)
switch(...){
case ...:
...
break;
case ...:
...
break;
default:
...
break;
}
5)for循环
for(int i=0;i<10;i++){
...
}
6)while循环
while(...){
...
}
7)do…while循环
do{
...
}while(...);
4、数据保存位置
1)栈内存
Java编译器必须准确的知道栈内存中保存的所有数据的长度以及存在时间,这是由于它必须生成相应的代码,以便向上和向下移动指针。而函数中声明的基本类型变量和对象的引用变量大小是已知的,存在时间也只是在这个函数中,所以它们放在栈内存中。每当程序调用函数时,就会为函数创建一个方法栈,函数中声明的基本类型变量和对象的引用变量就放在方法栈中,函数结束了,方法栈就释放了。
int a=3;
int b=3;
编译器会先处理int a=3;
首先它会在栈中创建一个变量为a的引用,然后查找占中是否有3
这个值,如果没找到,则将3
存放进来,然后将a指向3。接着处理int b=3;
,在创建b的引用变量后,因为栈中已经有了3
这个值,所以就直接令b指向3。
2)堆内存
编译器不必知道要从堆中分配多少存储空间,也不必知道存储的数据要在堆里停留多长时间,因此用堆保存数据会得到更大的灵活性。对象和数组的大小是不定的,所以对象和数组是存储在堆内存中的。
3)方法区
方法区和堆一样,是所有线程共享的内存区域,保存系统的类信息,比如类的字段、方法、常量池等。
4)运行常量池
在类加载后运行常量池会存放编译器生成的各种字面量(文本字符串、声明为final的常量值等)、符号引用(类和接口的全限定名、字段的名称和描述符、方法的名称和描述符)。常量池属于类信息的一部分,而类信息反映到JVM内存模型中是对应于JVM内存模型的方法区,也就是说类信息的常量池概念是存在于方法区中的。
5、字符串
1)String
String对象是不可变的,每一个看起来会修改String值得方法,实际上都是创建了一个全新的String对象。
方式一:
String str="abc";
过程:首先定义一个str的String类型的引用存放在栈中,再在字符串常量池中查找是否存在内容为”abc”的字符串对象,如果不存在则在字符串常量池中创建一个”abc”的字符串对象,并让str引用该对象;如果存在则直接让str引用该对象。
方式二:
String str=new String("abc");
过程:首先定义一个str的String类型的引用存放在栈中,再在字符串常量池中查找是否存在内容为”abc”的字符串对象,如果不存在则在字符串常量池中创建一个”abc”的字符串对象;如果存在则进行下一步。然后执行new操作,在堆中创建一个指定的对象”abc”,这里的对象是字符串常量池”abc”对象的一个拷贝对象,让str指向堆中”abc”这个对象。即每次使用new都会创建一个新的拷贝对象。
2)可变字符串
- StringBuffer:线程安全。
- StringBuilder:速度快。
3)使用策略
尽量不要使用”+”来进行频繁的拼接字符串,如果要连接字符串,应当使用StringBuffer和StringBuilder类。如果操作少量的数据,用String;单线程操作大量数据,用StringBuilder;多线程操作大量数据,用StringBuffer。
二、面向对象
1、封装
封装(Encapsulation):是指一种将抽象性函式接口的实现细节部分包装、隐藏起来的方法。可以被认为是一个保护屏障,防止该类的代码和数据被外部类定义的代码随机访问,要访问该类的代码和数据,必须通过严格的接口控制。
功能:在于我们能修改自己的实现代码,而不用修改那些调用我们代码的程序片段。适当的封装可以让程式码更容易理解与维护,也加强了程式码的安全性。
2、继承
1)介绍
继承:对现有类加以利用,并为其添加新功能的一种有效途径。
类的继承格式:
class 父类 {
}
class 子类 extends 父类 {
}
继承初始化:java运行时,第一件事情就是装载程序到外面找到那个类,在装载过程中,装载程序注意到它有一个基类,所以随之载入,若基类有另一个基类,则另一个基类也会被载入,以此类推。接下来,会在根基类执行static初始化,再在下一个衍生类执行,以此类推,保证这个顺序是非常关键的,因为衍生类的初始化可能要依赖与对基类成员的正确初始化。此时,必要的类已装载完毕,所以能够创建对象,首先,这个对象中的所有基本数据类型都会设置为它们的默认值,而将对象句柄设置为null。
2)类再生方式
- 合成:在新类中简单的创建原有类的对象。我们只是简单的创建原有类的功能,而不是它的形式。
- 继承:创建一个新类,继承原有类。
选择合成还是继承?
如果想在新类内部利用一个现有类的特性,而不想使用它的接口,通常应选择合成,也就是说,我们可以嵌入一个对象,使自己能使用它实现新类的特性,但新类的用户会看到我们已定义的接口,而不是来自嵌入对象的接口,考虑到这种效果,我们需要在新类里嵌入现有类的private对象。
在面向对象的程序设计中,创建和使用代码最可能采取的一种做法是,将数据和方法封装到一个类中,并且使用那个类的对象,而继承是最少见的一种做法。
为判断自己到底使用合成还是继承,一个最简单的办法就是考虑是否需要从新类上溯造型到基础类,如需要上溯,就需要继承,如果不需要买就需要提醒自己防止继承的滥用。
3、多态
多态:同一个行为具有多个不同表现形式或形态的能力,同一个接口,使用不同的实例而执行不同操作。
对于基类的句柄,赋值为不同的子类对象,当我们使用基类的句柄调用方法时可能出现不同效果,因为实际上是调用不同的子类的方法。
Shape
|-Circle
|-Square
public class ShapeTest{
public static Shape randShape(){
switch((int)(Math.random()*2)){
case 0:return new Circle();
case 1:return new Square();
}
}
public static void main(String[] args){
Shape[] s=new Shape[4];
for(int i=0;i<s.length;i++){
s[i]=randShape();
}
for(int i=0;i<s.length;i++){
s[i].draw();
}
}
}
4、重载
重载(overloading): 是在一个类里面,方法名字相同,而参数不同,返回类型可以相同也可以不同。
好的名字可以让程序员更好的了解代码,如果我们需要使用不同的方式实现同一个功能,我们只需要使用相同的函数名,而只改变其参数类型进行区分即可。
5、重写
重写(overwrite):是子类对父类的允许访问的方法的实现过程进行重新编写,返回值和形参都不能改变。即外壳不变,核心重写!重写的好处在于子类可以根据需要,定义特定于自己的行为。
对于父类的方法,子类想要以不同的方式实现同样的功能,以表现自己的独特性。
6、抽象
抽象类:如果一个类中没有包含足够的信息来描绘一个具体的对象,则定义为抽象类。
抽象方法:如果类中一个方法不确定它的具体实现,则定义为抽象方法,让子类进行实现。
7、接口
接口(interface):抽象方法的集合,是更深一层的抽象,可以看作只有抽象方法的抽象类,只提供方法形式,而不包含具体的实现。
接口特性:
- 接口中每一个方法也是隐式抽象的,接口中的方法会被隐式的指定为 public abstract(只能是 public abstract,其他修饰符都会报错)。
- 接口中可以含有变量,但是接口中的变量会被隐式的指定为 public static final 变量(并且只能是 public,用 private 修饰会报编译错误)。
- 接口中的方法是不能在接口中实现的,只能由实现接口的类来实现接口中的方法。
抽象类和接口的区别:
- 抽象类中的方法可以有方法体,就是能实现方法的具体功能,但是接口中的方法不行。
- 抽象类中的成员变量可以是各种类型的,而接口中的成员变量只能是 public static final 类型的。
- 接口中不能含有静态代码块以及静态方法(用 static 修饰的方法),而抽象类是可以有静态代码块和静态方法。
- 一个类只能继承一个抽象类,而一个类却可以实现多个接口。
三、集合泛型
1、Collection
一个独立元素的序列。
2、Map
一组成对的键值对对象,允许使用键来获取值。
3、泛型
泛型:为了编写应用于多种类型的代码,使类或方法具备更广泛的作用。
四、I/O流
1、字符流
2、字节流
3、使用
IO流按使用来分类,可以分为节点流和处理流两类。
1)节点流
该类型可以从或者向一个特定的地点读写数据。
类型 | 字符流 | 字节流 |
---|---|---|
File | FileReader FileWriter | FileInputStream FileOutputStream |
Memory Array | CharArrayReader CharArrayWriter | ByteArrayInputStream ByteArrayOutputStream |
Memory String | StringReader StringWriter | |
Pipe(管道) | PipedReader PipedWriter | PipedInputStream PipedOutputSream |
2)处理流
该类型是通过对现有流的封装来实现对数据的读写,这种类型的流的构造方法会将其它流作为参数。
(1)缓冲流
缓冲流用来提高流的操作效率,包含有:
BufferedInputStream
BufferedOutputStream
BufferedReader
BufferedWriter
(2)转换流
该类型是字节流和字符流的之间架设的桥梁,可以对读取到的字节数据进行指定编码的编码转换。
InputStreamReader
OutputStreamWriter
(3)数据流
数据流可以方便的对一些基本类型的数据进行直接的存储和读取,不需要再进一步进行转换,通常只操作基本数据类型的数据,就需要通过DataStream进行包装。
DataInputStream
DataOutputStream
4、File
File类是对文件系统图中文件以及文件夹进行封装的对象,可以通过对象的思想来操作文件和文件夹。File类保存文件或目录的各种元数据信息,包括文件名、文件长度、最后的修改时间、是否刻度、获取当前文件的路径名,判断指定文件是否存在,获得当前目录中的文件列表,创建、删除文件和目录等方法。
5、RandomAccessFile
RandomAccessFile类并不是流体系中的一员,其中封装了字节流,同时还封装了一个缓冲区(字符数组),通过内部的指针来操作字符数组中的数据。
特点:
- 该对象只能操作文件,所以构造函数接收两种类型的参数:字符串文件路径、FIle对象。
- 该对象既可以对文件进行读操作,也能进行写操作,在进行对象实例化时可指定操作模式(r,rw)。
五、多线程
1、生命周期
- 新建状态:创建一个线程对象后。
- 就绪状态:调用了start()方法后,线程处于就绪队列中,等待调度。
- 运行状态:获取CPU资源后,就可以执行run()方法,
- 阻塞状态:线程执行了sleep(睡眠)、suspend()挂起等方法,失去占用资源之后
- 死亡状态:运行的线程完成任务或者其它终止条件发生时。
2、优先级
每一个 Java 线程都有一个优先级,这样有助于操作系统确定线程的调度顺序。Java 线程的优先级是一个整数,其取值范围是 1 (Thread.MIN_PRIORITY ) - 10 (Thread.MAX_PRIORITY )。默认情况下,每一个线程都会分配一个优先级 NORM_PRIORITY(5)。具有较高优先级的线程对程序更重要,并且应该在低优先级的线程之前分配处理器资源。但是,线程优先级不能保证线程执行的顺序,而且非常依赖于平台。
3、创建线程
1)实现Runnable接口
创建一个实现Runnable接口的类,添加一个start方法,将该类传入Thread对象中,来启动线程。
class RunnableDemo implements Runnable{
private Thread t;
@override
public void run(){
}
public void start(){
if(t==null){
t=new Thread(this);
t.start();
}
}
}
启动线程
Runnable r=new RunnableDemo();
r.start();
2)继承Thread类
创建一个类继承Thread类,重写run方法,然后创建该类的示实例,调用start方法来执行。
class ThreadDemo extends Thread{
@override
public void run(){
}
}
启动线程
new ThreadDemo().start();
3)实现Collable接口
创建Callable接口的实现类,并实现call方法。
public class CallableDemo implements Callable<Integer>{
@override
public Integer call() throw Exception{
}
}
启动线程
CallableDemo cd=new CallableDemo();
FutureTask<Integer> ft=new FutureTask<>(cd);
new Thread(ft).start();
六、数据存储
private static String url = "jdbc:mysql://localhost:3306/dangdang?useUnicode=true&characterEncoding=utf-8&useSSL=false";
private static String user = "root";
private static String password = "root";
private static String driver = "com.mysql.jdbc.Driver";
1、加载驱动
static {
try {
Class.forName(driver);
} catch (ClassNotFoundException e) {
throw new ExceptionInInitializerError(e);
}
}
2、建立连接
public Connection getCon() {
Connection connection = null;
try {
connection = DriverManager.getConnection(url, user, password);
} catch (SQLException e) {
e.printStackTrace();
}
return connection;
}
3、执行操作
4、释放连接
public void close(Connection con, PreparedStatement ps, ResultSet rs) {
try {
if (rs != null)
rs.close();
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
if (ps != null) ps.close();
} catch (SQLException e) {
e.printStackTrace();
} finally {
if (con != null) {
try {
con.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
}
七、网络编程
1、Socket
1)服务器
- 监听端口:服务器启动后,监听本地某个固定端口。
- 获得连接:当客户端连接到服务器端时,服务器就可以获得一个连接,包含客户端的信息。
- 交换数据:服务器通过获得的连接进行数据交换,先接收再发送。
- 关闭连接:当服务器程序关闭时需要关闭服务器端。通过关闭服务器端使得都唔起监听的端口以及占用的内存释放出来。
2)客户端
- 建立连接:客户端指定连接到的服务器的IP地址和端口号来建立连接。
- 交换数据:通过连接来交换数据,由客户端发送请求道服务器,服务器返回结果给客户端。
- 关闭连接:数据交换完成后,关闭网络连接,释放程序占用的端口、内存等系统资源。
2、TCP
public class TCPSocketUtils{
private ServerSocket serverSocket = null;
private Socket socket = null;
private OutputStream os = null;
private InputStream is = null;
public void server(int port){
try{
//监听端口
serverSocket=new ServerSocket(port);
//建立连接
socket=serverSocket.accept();
//初始化流
is=socket.getInputStream();
os=socket.getOutputStream();
byte[] b=new byte[1024];
int n;
while((n=is.read(b))>0){
os.write(b,0,n);
}
}catch(Exception e){
e.printStackTrace();
}finally{
try{
os.close();
is.close();
socket.close();
serverSocket.close();
}catch(Exception e1){
e1.printStackTrace();
}
}
}
public void client(String ip,int port,String data){
try{
//建立连接
socket=new Socket(ip,port);
//初始化流
os=socket.getOutputStream();
is=socket.getInputStream();
byte[] b=new byte[1024];
os.write(data.getBytes());
int n;
while((n=is.read(b))>0){
System.out.print(new String(b,0,n));
}
}catch(Exception e){
e.printStackTrace();
}finally{
try{
is.close();
os.close();
socket.close();
}catch(Exception e1){
e1.printStackTrace();
}
}
}
}
3、UDP
public class UDPSocketUtils{
private DatagramSocket datagramSocket = null;
private DatagramPacket sendDP = null;
private DatagramPacket receiveDP = null;
public void server(int port){
try{
byte[] b=new byte[1024];
receiveDP=new DatagramPacket(b,b.length);
//监听端口
datagramSocket=new DatagramSocket(port);
while(true){
datagramSocket.receive(receiveDP);
new LogicThread(datagramSocket,receiveDP);
}
}catch(Exception e){
e.printStackTrace();
}finally{
try{
datagramSocket.close();
}catch(Exception e1){
e1.printStackTrace();
}
}
}
public void client(String ip,int port,String data){
try{
//建立连接
DatagramSocket datagramSocket=new DatagramSocket();
byte[] b=data.getBytes();
InetAddress address=InetAddress.getByName(host);
//发送数据包对象
sendDP=new DatagramPacket(b,b.length,address,port)
datagramSocket.send(sendDp);
//初始化接收数据
byte[] b1=new byte[1024];
receiveDP=new DatagramPacket(b,b.length);
datagramSocket.receive(receiveDP);
//读取反馈内容,并输出
byte[] response=receiveDP.getData();
int len=receiveDP.getLength();
String s=new String(response,0,len);
System.out.println(s);
}catch(Exception e){
e.printStackTrace();
}finally{
try{
datagramSocket.close();
}catch(Exception e1){
e1.printStackTrace();
}
}
}
}
public class LogicThread extends Thread{
private DatagramSocket datagramSocket;
private DatagramPacket datagramPacket;
public LogicThread(DatagramSocket datagramSocket,DatagramPacket datagramPacket){
this.datagramSocket=datagramSocket;
tihs.datagramPacket=datagramPacket;
start();
}
public void run(){
try{
byte[] data=datagramPacket.getData();
int len=datagramPacket.getLength();
InetAddress address=datagramPacket.getAddress();
int port=datagramPacket.getPort();
//输出
System.out.println("客户端IP:" + address.getHostAddress());
System.out.println("客户端端口号:" + port);
System.out.println("客户端发送内容:" + new String(data,0,len));
//反馈数据到客户端
byte b="OK".getBytes();
DatagramPacket sendDP=new DatagramPacket(b,b.length,address,port);
datagramSocket.send(sendDP);
}catch(Exception e){
e.printStackTrace();
}
}
}
4、案例
基于TCP的上传与下载
import java.io.BufferedInputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class FileUp{
// 上传的文件路径
private String filePath;
// socket服务器地址和端口号
private String host;
private int port;
public String getFilePath() {
return filePath;
}
public void setFilePath(String filePath) {
this.filePath = filePath;
}
public int getPort() {
return port;
}
public void setPort(int port) {
this.port = port;
}
public String getHost() {
return host;
}
public void setHost(String host) {
this.host = host;
}
public static void main(String[] args) {
FileUp fu = new FileUp();
fu.setHost("127.0.0.1");
fu.setPort(9005);
fu.setFilePath("f:\\soft\\");
fu.uploadFile("DbVisualizer.rar");
}
/**
* 客户端文件上传
* @param fileName 文件名
*/
public void uploadFile(String fileName) {
Socket s = null;
try {
s = new Socket(host, port);
// 选择进行传输的文件
File fi = new File(filePath + fileName);
System.out.println("文件长度:" + (int) fi.length());
DataInputStream fis = new DataInputStream(new FileInputStream(filePath + fileName));
DataOutputStream ps = new DataOutputStream(s.getOutputStream());
ps.writeUTF(fi.getName());
ps.flush();
ps.writeLong((long) fi.length());
ps.flush();
int bufferSize = 8192;
byte[] buf = new byte[bufferSize];
while (true) {
int read = 0;
if (fis != null) {
read = fis.read(buf);
}
if (read == -1) {
break;
}
ps.write(buf, 0, read);
}
ps.flush();
// 注意关闭socket链接哦,不然客户端会等待server的数据过来,
// 直到socket超时,导致数据不完整。
fis.close();
ps.close();
s.close();
System.out.println("文件传输完成");
} catch (Exception e) {
e.printStackTrace();
}
}
}
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.FileOutputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class FileDown extends Thread {
// 文件的保存路径
private String fileDir;
// socket服务器端口号
private int port;
// 是否停止
private boolean stop;
public String getFileDir() {
return fileDir;
}
public void setFileDir(String fileDir) {
this.fileDir = fileDir;
}
public int getPort() {
return port;
}
public void setPort(int port) {
this.port = port;
}
public boolean isStop() {
return stop;
}
public void setStop(boolean stop) {
this.stop = stop;
}
public static void main(String[] args) {
FileDown fd = new FileDown();
fd.setFileDir("e:\\");
fd.setPort(9005);
fd.start();
}
/**
* 文件下载
*/
@Override
public void run() {
Socket socket = null;
try {
ServerSocket ss = new ServerSocket(port);
do {
socket = ss.accept();
// public Socket accept() throws
// IOException侦听并接受到此套接字的连接。此方法在进行连接之前一直阻塞。
System.out.println("建立socket链接");
DataInputStream inputStream = new DataInputStream(
new BufferedInputStream(socket.getInputStream()));
// 本地保存路径,文件名会自动从服务器端继承而来。
int bufferSize = 8192;
byte[] buf = new byte[bufferSize];
long passedlen = 0;
long len = 0;
// 获取文件名
String file=fileDir + inputStream.readUTF();
DataOutputStream fileOut = new DataOutputStream(
new BufferedOutputStream(new FileOutputStream(file)));
len = inputStream.readLong();
System.out.println("文件的长度为:" + len + "\n");
System.out.println("开始接收文件!" + "\n");
while (true) {
int read = 0;
if (inputStream != null) {
read = inputStream.read(buf);
}
passedlen += read;
if (read == -1) {
break;
}
// 下面进度条本为图形界面的prograssBar做的,这里如果是打文件,可能会重复打印出一些相同的百分比
System.out.println("文件接收了" + (passedlen * 100 / len)
+ "%\n");
fileOut.write(buf, 0, read);
}
System.out.println("接收完成,文件存为" + file + "\n");
fileOut.close();
} while (!stop);
} catch (Exception e) {
System.out.println("接收消息错误" + "\n");
e.printStackTrace();
return;
}
}
}
八、异常处理
1、基本概念
异常:当出现程序无法控制的外部环境问题时,java就会用异常对象来描述。
异常发生原因:
- 用户输入了非法数据
- 要打开的文件不存在
- 网络通信时连接中断,或者JVM内存溢出
2、常用异常
3、处理异常
- 捕获异常
try{
}catch(Exception e){
e.printStackTrace();
}finally{
}
执行顺序:当try没有捕获到异常时,try中语句逐一被执行,然后执行finally语句块;当try捕获到异常后,匹配catch语句块中处理此异常的情况,执行完后,执行finally中的语句。
- 抛出异常
throw ThrowableInstance;
这里的ThrowableInstance是Throwable类类型或者Throwable子类类型的一个对象。程序执行完throw后立即停止,throw后面的语句不被执行。
public void func() throws Exception{
}
一个方法导致了一个异常但是不处理它,必须指定这种行为以使方法的调用者可以保护它们自己而不发生异常。
相关文章
- 暂无相关文章
用户点评