JavaSE重要知识点梳理
1、==、equals、 instanceof
1、 ==
== ——>是运算符
1、 如果比较的是基本数据类型变量:比较的是俩个变量保存的数据是否相等(类型不一定相同)
例如:
int a =10;
char c=10;
System.out.println(a==c);//true
2、如果比较的是俩个引用数据类型变量:比较的是内存地址
例如:
String s = new String("臭猪");
String s1 = new String("臭猪");
s==s1 //false
//false
Teacher t1 = new Teacher("王荣远", 22);
Teacher t2 = new Teacher("王荣远", 22);
t1==t2 //false
2 、equals
equals ——>是方法 ,只能适用与引用类型变量
equals方法有俩个:
-
一个类如果没有重写Object中的equals方法:可以看到与==相同
public boolean equals(Object obj) { return (this == obj); }
-
一个是String中重写了equals()方法,比较的是对象里的实体内容是否相同(其他很多类都重写了equals方法,如:Date、File....)
3、 instanceof
判断左右俩边是否存在父子关系-—> 存在—>编译通过—>再判断右边的类是否是(运行时类型)左边对象的本类/父类*
不存在——>编译报错
//父类Person
Person per=new Person();
//子类 Teacher Student
Teacher tea= new Teacher();
Student stu=new Student();
//以原始类型比较 左边 右边
System.out.println(stu instanceof Person);//true
System.out.println(stu instanceof Student);//true
System.out.println(per instanceof Student);//false
System.out.println(stu instanceof Teacher);//编译报错
//当有类型转换时
System.out.println(per instanceof Student);//false
per=new Student();//运行时类型
System.out.println(per instanceof Student);//true
2、内部类
内部类:
- 提供了更好的封装
- 不允许其他类访问(同一个包也不行)
- 比外部类可以多用三个修饰符:private、protected、static
(此修饰符在外部类以外使用时,有大区别)
1、非静态内部类(成员内部类)
1、创建:
-
不使用static修饰,
-
不可创建static成员
-
可以调用外部类的static/非static成员
2、创建结构:
public class 非Static外部类 {
int parrentA=10;
static int parrentB=20;
void A(){};
static void B(){}
//非静态内部类
class people{
//初始化块
{
a=100;
}
//成员变量
int a=1;
//成员方法
void test(){
A();//调用外部类的成员方法
B();//调用外部类的static方法
}
//构造方法
public people(){
}
//内部类
class son{}
}
}
3、使用
2、静态内部类
1、创建:
- 使用static修饰,
- 可以创建static/非static的变量和方法
- 只能调用外部类的static成员
2、创建结构:基本无区别
3、使用:
3、抽象类(abstract、interface)
3.1 abstract
可以定义:
- 成员变量
- 方法(抽象方法/普通方法)
- 构造器
- 方法块
- 内部类
3.2 interface
可以定义:
-
静态常量
-
方法(抽象方法/静态方法)
-
方法块
4、集合
(本质:java是先实现了HashMap集合,然后包装一个所有value都为空对象的Map集合实现了Set集合类)
HashSet:对于所有的Hash和其子类来说,都采用Hash算法:来计算元素的存储位置、和计算集合的大小
HashMap:对于所有的Map和其子类来说,都采用Hash算法:来决定Key元素的存储位置、和增加Key集合的大小
5、 线程同步
5.1 synchronized 同步
方式一 : 同步代码块
synchronized(同步监视器){
//需要被同步的代码
}
//1、操作共享数据的代码,被称为需要被同步的代码
//2、共享数据:多个线程共同操作的变量
//3、同步监视器(俗称):锁,任何一个类的对象,都可以充当锁
要求:多个线程必须共用一把锁,即一个对象!!!
在Runnable 中:由于共享变量,所以obj从头到尾都是一个锁
public class syn_win_Run implements Runnable{
private int ticket=50;
private Object obj =new Object();
@Override
public void run() {
while(true){
synchronized(obj){//如果在这里使用new Object(),那用的就不是一个锁
if(ticket>=1){
System.out.println(Thread.currentThread().getName()+"卖第:"+ticket+"张票");
ticket--;
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
} else{
break;
}
}
}
}
}
在Thread中:注意这里使用的变量都是static
private static int ticket=50;
private static Object obj =new Object();
@Override
public void run() {
while(true){
synchronized(obj){//这里使用的变量都是static(obj、ticket)
if(ticket>=1){
System.out.println(Thread.currentThread().getName()+"卖第:"+ticket+"张票");
ticket--;
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
} else{
break;
}
}
}
}
方式二:同步方法
在Runnable中:即将synchronized加到方法上使用,与同步代码块的使用基本无区别
private int ticket = 50;
public void run() {
while(true){
show();//调用方法
if(ticket<=0)
break;
}
}
public synchronized void show() {
if (ticket >= 1) {
System.out.println(Thread.currentThread().getName() + "卖第:" + ticket + "张票");
ticket--;
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
在Thread中:变量为static,同步方法也要修饰为static,(核心思想:使用一个对象,一把锁)
public class syn_win_Thread extends Thread{
private static int ticket=50;
@Override
public void run() {
while(true){
show();
if(ticket<=0)
break;
}
}
public static synchronized void show(){//注意同步方法改为类方法了
if(ticket>=1) {
System.out.println(Thread.currentThread().getName() + "卖第:" + ticket + "张票");
ticket--;
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
同步方法总结:
- 同步方法仍然涉及到同步监视器,只是我们不需要我们显示申明
- 非静态的同步方法,同步监视器是:this
- 静态的同步方法,同步监视器是类本身
5.2 Lock锁同步
使用在Runnable中:与使用同步代码基本没有区别
class weindow implements Runnable{
private int ticket=50;
private ReentrantLock lock= new ReentrantLock();
public void run() {
while(true){
lock.lock();//加锁
try{
if(ticket>=1){
System.out.println(Thread.currentThread().getName()+"卖第:"+ticket+"张票");
ticket--;
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
} else{
break;
}
}finally {
lock.unlock();
}
}
}
}
使用在Thread中:只需将公用的变量设置为static, Lock无需static设置
class window extends Thread{
private static int ticket=50;
private ReentrantLock lock= new ReentrantLock();
public void run() {
while(true){
lock.lock();//加锁
try{
if(ticket>=1){
System.out.println(Thread.currentThread().getName()+"卖第:"+ticket+"张票");
ticket--;
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
} else{
break;
}
}finally {
lock.unlock();
}
}
}
}
5.3 俩者的异同
相同:都可以解决线程安全问题、
不同:synchronized在执行完相应的代码块后,自动释放锁
Lock 是手动 启动、释放
建议使用顺序:Lock锁——>synchronized代码块——>synchronized方法
6、String/StringBuffer/StringBuild
7、并发
8、反射
1、能够获取类的结构
// 利用类路径获取类
Class c1 = Cless.forName("类的详细地址") ;
// 利用具体类的Class属性获取
Class c2 = Person.class;
// 通过实例获取
Class c3 = person.getClass();
// 一个加载类在JVM中只有一个Class示例
2、类的初始化:
主动引用:
- 虚拟机启动,先初始化main方法所在类
- new 一个类的对象
- 调用类的静态成员(除了final常量)和静态方法
- 使用java.long.reflect包的方法对类进行反射调用
- 初始化某类时其父类未初始化,则先初始化父类
被动引用:
- 访问一个静态域时,只有真正申明这个域的类才会被初始化
- 数组定义类引用
- 引用常量
3、拥有Class对象的类型:
class、interface、数组、enum、annotation、基础数据类型、void
9、泛型
10、设计模式
代理:
单例:
工厂:
。。。。(手写)
11、网络编程
1、基础
1.1、OSI七层模型
OSI七层网格模型 | TCP/IP四层概念模型 | 对应网络协议 |
---|---|---|
应用层 | 应用层 | HTTP, TFTP, FTP, NFS, WAIS, SMTP |
表示层 | Telnet, Rlogin, Snmp, Gopher | |
会话层 | SMTP, DNS | |
传输层 | 传输层 | TCP, UDP |
网络层 | 网络层 | IP, ICMP, ARP, RARP, AKP, UUCP |
数据链路层 | 数据链路层 | FDDI, Ethernet, Arpanet, PDN, SLIP, PPP |
物理层 | IEEE 802.1A, IEEE 802.2到IEEE 802.11 |
1.2、常用的端口号
端口表示计算机上一个程序的进程
- 不同的进程由不同的端口,用来区分软件
- 按规定0~65535,不能使用相同的端口
- 单个协议下,端口号不能冲突
- 因此,如果TCP使用80 UDP也使用80,互不影响,
端口分类:
-
公有端口:0~1023(尽量不用)
- HTTP:80
- HTTPS:443
- FTP:21
- Telent:23
-
程序注册端口:1024~49151,分配用户或者程序
- Tomcat:8080
- MySQL:3306
- Oracle:1521
-
动态、私有:49152~65535(尽量不用)
1.3、InetAddress
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Arrays;
//测试IP
//由于没有构造器,不能new出来。只能利用静态方法
public class TestInetAddress {
public static void main(String[] args) {
try {
//查询本机地址
InetAddress inetAddress1 = InetAddress.getByName("127.0.0.1");
System.out.println(inetAddress1);
InetAddress inetAddress3 = InetAddress.getByName("localhost");
System.out.println(inetAddress3);
InetAddress inetAddress4 = InetAddress.getLocalHost();
System.out.println(inetAddress4);
//查询网站ip地址
InetAddress inetAddress2 = InetAddress.getByName("www.baidu.com");
System.out.println(inetAddress2);
//常用方法
System.out.println(Arrays.toString(inetAddress2.getAddress()));//返回一个数组
System.out.println(inetAddress2.getCanonicalHostName());//规范的名字
System.out.println(inetAddress2.getHostAddress());//ip
System.out.println(inetAddress2.getHostName());//域名,或者自己电脑的名字
} catch (UnknownHostException e) {
e.printStackTrace();
}
}
}
InetAddress 获取地址
InetAddress.getCanonicalHostName 规范的名字
InetAddress.getHostAddress IP
InetAddress.getHostName 域名或自己电脑的名字
1.4、InetSocketAddress
- 找到电脑上特定端口,或有其对应的处理程序,才能收到发出的程序
//端口
public class TestInetSocketAddress {
public static void main(String[] args) {
InetSocketAddress socketAddress = new InetSocketAddress("127.0.0.1",8080);
InetSocketAddress socketAddress2 = new InetSocketAddress("localhost",8080);
System.out.println(socketAddress);
System.out.println(socketAddress2);
System.out.println(socketAddress.getAddress());
System.out.println(socketAddress.getHostName()); //地址
System.out.println(socketAddress.getPort()); //端口
InetSocketAddress IP 地址及端口
InetAddress IP 地址
1.5、通信协议【TCP/UDP】
主要使用:
- TCP:用户传输协议【类似于打电话,需要俩边进行连接】
- UDP:用户数据报协议【相当于发短信,不需要俩边进行i按揭,但不一定送到】
TCP
-
需要通信双方进行连接
-
连接稳定
-
客户端——》服务端:主动和被动的过程
-
传输完成——》释放连接:效率低
-
三次握手,四次挥手
最少需要三次,保证稳定连接 A—— 我要连接 ——>B B—— 你可以连接 ——>A A—— 那我连接了 ——>B 连接成功! 四次挥手 A——我要断开——>B B——你可以断开——>A B——你确定断开?——>A A——我确定断开!——>B 连接断开
UDP
- 不需要连接
- 不稳定
- 客户端、服务端没有明确的界限
- 传输效率高
1.6、TCP使用
TCP的使用需要明确客户端和服务器端的职责
服务器:
- 得有一个端口号
- 对端口号实时监听
- 或得客户端传来的消息
客户端:
- 要知道服务器的地址、要连接的端口号
- 创建连接
- 发送消息
案例1、:编写一个简单的聊天发送的实现
服务器端
public class Server {
public static void main(String[] args) {
try {
//1、我得创建一个端口
ServerSocket serverSocket = new ServerSocket(9999);
//2、对端口实行监听,等待客户端来连接
Socket accept = serverSocket.accept();
//3、获得输入流,读取信息,并输出
InputStream is = accept.getInputStream();
byte[] buffer = new byte[1024];
int len;
ByteArrayOutputStream baos = new ByteArrayOutputStream();//byte类型数组管道输出流
while((len=is.read(buffer))!=-1){
baos.write(buffer,0,len);
}
System.out.println(baos.toString());
//关闭资源
if(baos!=null){baos.close();}
if(is!=null){is.close();}
if(serverSocket!=null){serverSocket.close();}
} catch (Exception e) {
e.printStackTrace();
}
}
}
客户端
public class Client {
public static void main(String[] args) {
try {
//1、需要得到服务器的IP和端口号
InetAddress localhost = InetAddress.getByName("localhost");
int port=9999;
//2、建立连接
Socket socket = new Socket(localhost, port);
//3、传输信息
OutputStream os = socket.getOutputStream();
os.write("真帅".getBytes());
//关闭连接
if(os!=null){os.close();}
if(socket!=null){socket.close();}
} catch (Exception e) {
e.printStackTrace();
}
}
}
案例2、文件上传
服务器端:
//服务器端接收
public class FileOut {
public static void main(String[] args) {
try{
//设置端口
ServerSocket serverSocket = new ServerSocket(9999);
//设置端口的监听
Socket accept = serverSocket.accept();
//获得输入流,读取信息
InputStream is = accept.getInputStream();
//写入文件
FileOutputStream fos = new FileOutputStream(new File("out.JPG"));
byte[] buffer = new byte[1024];
int len=0;
while((len=is.read(buffer))!=-1){
fos.write(buffer,0,len);
}
//关闭资源
if(fos!=null){fos.close();}
if(is!=null){is.close();}
if(serverSocket!=null){serverSocket.close();}
}catch (Exception e){
}
}
}
客户端:
//客户端发送
public class FileIN {
public static void main(String[] args) {
try {
//1、需要得到服务器的IP和端口号
InetAddress localhost = InetAddress.getByName("localhost");
int port=9999;
//2、建立连接
Socket socket = new Socket(localhost, port);
//3、传输信息,创建要传输的文件,并写入到缓冲区中
FileInputStream fis = new FileInputStream(new File("in.JPG"));
OutputStream os = socket.getOutputStream();
int len=0;
byte[] buffer = new byte[1024];
while((len=fis.read(buffer))!=-1){
os.write(buffer,0,len);
}
//关闭连接
if(os!=null){os.close();}
if(socket!=null){socket.close();}
} catch (Exception e) {
e.printStackTrace();
}
}
}
1.7、UDP使用
- 不用连接服务器,但是需要知道对方的地址和端口号
- 需要俩个包:DatagramPacket、DatagramSocket(流)
案例1、发送消息
1、创建发送端:
public class Client {
public static void main(String[] args)throws Exception {
//1、建立Socket
DatagramSocket datagramSocket = new DatagramSocket();
//2、创建包并发送
String msg="你好啊";//发送的消息
int port=9999;//接收方的端口号
InetAddress localhost = InetAddress.getByName("localhost");//接收方的IP
DatagramPacket packet = new DatagramPacket(msg.getBytes(),0,msg.getBytes().length,localhost,port);
//3、发送包
datagramSocket.send(packet);
//4、关闭流
datagramSocket.close();
}
}
创建接收端:
public class Server {
public static void main(String[] args)throws Exception {
//1、开放端口,等待连接
DatagramSocket datagramSocket = new DatagramSocket(9999);
//2、接收数据包
byte[] buffer = new byte[1024];
DatagramPacket packet = new DatagramPacket(buffer,0,buffer.length);
//阻塞接收【相当于监听】
datagramSocket.receive(packet);
//4、读取消息
System.out.println(new String(packet.getData(),0,packet.getData().length));
//4、关闭流
datagramSocket.close();
}
}
案例2、实现聊天
思路:既然是发送和接收,理解为俩种行为,一个人可以具有俩种行为,数据可以使用System.in,使用包装流包装
-
创建发送接收方法到线程中
发送端
public class Sender implements Runnable{ DatagramPacket packet; DatagramSocket socket; BufferedReader bufferedReader; private int toport; //使用构造方法获取要发送的端口号 public Sender(int toport) { this.toport=toport; try{ socket=new DatagramSocket(); }catch (Exception e){} } @Override public void run() { while(true){ try{ bufferedReader = new BufferedReader(new InputStreamReader(System.in)); String msg=bufferedReader.readLine(); //获得IP InetAddress IP = InetAddress.getByName("localhost"); packet=new DatagramPacket(msg.getBytes(),0,msg.getBytes().length,IP,toport); socket.send(packet); //如果接收的消息是拜拜,就结束 if(msg.equals("拜拜")){ break; } }catch (Exception e){ e.printStackTrace(); } } socket.close(); } }
-
创建接收端
public class Receive implements Runnable{ DatagramSocket socket; DatagramPacket packet; int Myport; byte[] buffer; String msg=null; String fromName; public Receive(int Myport,String fromName){ this.fromName=fromName; this.Myport=Myport; try{ socket=new DatagramSocket(Myport); }catch (Exception e){ } } @Override public void run() { try{ }catch (Exception e){} while(true){ try{ buffer=new byte[1024]; packet=new DatagramPacket(buffer,0,buffer.length); socket.receive(packet); msg=new String(packet.getData(),0,packet.getData().length); //如果接收的消息是拜拜,就结束 if(msg.equals("拜拜")){ break; } //输出消息 System.out.println(fromName+":"+msg); }catch (Exception e){ e.printStackTrace(); } } socket.close(); } }
-
创建使用者:Student
public class Student { public static void main(String[] args) { Sender sender = new Sender(9999); Receive receive = new Receive(8888,"老师"); new Thread(sender).start(); new Thread(receive).start(); } }
-
创建使用者:Teacher
public class Teacher { public static void main(String[] args) { Sender sender = new Sender(8888); Receive receive = new Receive(9999,"学生"); new Thread(sender).start(); new Thread(receive).start(); } }
1.8、俩者的区别
属性 | TCP | UDP |
---|---|---|
通信双方需要连接 | 不需要连接 | |
连接稳定 | 不稳定 | |
客户端/服务器:界限清晰 | 没有明确的界定 | |
传输完成——》释放连接:效率低 | 效率高 |
1.9、URL
常用方法
package chat;
import java.net.MalformedURLException;
import java.net.URL;
public class DRLDemo01 {
public static void main(String[] args) throws MalformedURLException {
URL url = new URL("http://localhost:8080/helloworld/index.jsp?username=kuangshen&password==123");
//协议http
System.out.println(url.getProtocol());
//主机ip,localhost
System.out.println(url.getHost());
//端口,8080
System.out.println(url.getPort());
//文件,/helloworld/index.jsp
System.out.println(url.getPath());
//全路径,/helloworld/index.jsp?username=kuangshen&password==123
System.out.println(url.getFile());
//参数,username=kuangshen&password==123
System.out.println(url.getQuery());
}
}
URL网络下载
package chat;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
public class UrlDown {
public static void main(String[] args) throws Exception {
//1.下载地址
URL url = new URL("https://**1.**2.com/**/**/***.jpg");
//2.连接到这个资源 HTTP
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
//3.输入流
InputStream inputStream = urlConnection.getInputStream();
//4.下载到存放地址
FileOutputStream fos = new FileOutputStream("123.jpg");
//5.写出数据
byte[] buffer = new byte[1024];
int len ;
while((len = inputStream.read(buffer))!=-1){
fos.write(buffer,0,len);
}
fos.close();
inputStream.close();
urlConnection.disconnect(); //断开连接
}
}