线程

基本概念


程序 - 数据结构 + 算法,主要指存放在硬盘上的可执行文件。
进程 - 主要指运行在内存中的程序。
目前主流的操作系统都支持多进程,是为了让操作系统同时执行多个任务,但进程是重量级的,新建进程对CPU和内存等系统资源的消耗比较大,因此进程的数量是有限的。
线程就是进程内部的程序流,也就是说操作系统中支持多进程,而每个进程中又可以支持多线程,并且线程是轻量级的,新建线程会共享所在进程的资源,因此对资源的消耗比较小,以后的开发中基本都采用多线程的技术。
目前主流的操作系统都采用时间片轮转法来保证多个任务的同时执行,叫做并发执行,也就是宏观并行,微观串行的技术。

线程的创建(重中之重)

1 Thread类
java.lang.Thread类用于描述线程,Java虚拟机中允许运行多个线程。
创建线程并启动的方式有两种:

  • 自定义类继承Thread类并重写run()方法,创建该类的对象调用start()方法。
  • 自定义类实现Runnable接口并重写run()方法,创建该类的对象作为创建Thread类对象的实参,然后使用Thread类的对象去调用start()方法。

2 相关的方法

Thread() - 使用无参的方式创建对象。
Thread(String name) - 使用参数指定的名称来创建对象。
Thread(Runnable target) - 根据参数指定的接口来构造对象。
- 接口作为方法的形参时,实参传递的方式有两种:
a.创建实现类的对象作为实参传递;
b.使用匿名内部类来得到接口的引用作为实参传递。
Thread(Runnable target, String name) - 根据接口引用和名称共同创建对象。
void run() - 若使用Runnable对象构造的线程对象,则调用该方法最终为调用                            Runnable对象中的run()方法,否则该方法不执行任何操作。
void start() - 用于启动线程,并自动调用该线程对象的run()方法。

实现原理(尽量理解)

main()方法是程序的入口,执行main()方法的线程叫做主线程;
由start()方法启动的线程叫做新/子线程。
对于start()方法之前的代码来说,由主线程执行一次,当start()方法调用成功后,线程的个数瞬间由1个变成了2个,其中新创建的线程去执行run()方法的代码,主线程继续向下执行,两个线程各自独立运行。
当run()方法结束后子线程结束,当main()方法结束后主线程结束,两个线程的执行先后次序没有明确的规定,由系统的调度算法来决定。

注意:
继承的方式创建和启动线程的代码简单,但Java支持单继承,不利于项目的维护和扩展,因此在以后的开发中推荐使用实现接口的方式创建和启动线程。

思考:
采用匿名内部类的方式来创建和启动一个线程呢??
解析:
父类/接口类型 引用变量名 = new 父类/接口类型(){ 方法的重写; };

线程的编号和名称(熟悉)

long getId() - 用于获取线程的标识符/编号并返回。
String getName() - 用于获取线程的名称并返回。
void setName(String name) - 用于将线程名称修改为参数指定的数值。
static Thread currentThread() - 用于返回当前正在执行线程对象的引用。

线程的主要状态(了解)

  • 使用new关键字创建线程对象后进入的状态。
  • 此时该线程并没有开始执行。
    就绪状态 - 调用start()方法后进入的状态。
  • 此时该线程仍然没有开始执行。
    运行状态 - 使用线程调度器调用就绪状态的线程后进入的状态。
  • 此时该线程开始执行。
  • 当时间片结束后线程的任务没有完成则回到就绪状态。
    消亡状态 - 当时间片结束后线程的任务已经完成后进入的状态。
    阻塞状态 - 当线程执行的过程中发生阻塞事件时进入的状态,如:sleep()方法。
  • 当阻塞状态解除后进入就绪状态。

线程的常用方法(重点)

static void sleep(long millis) - 用于让当前线程睡眠参数指定的毫秒数。
- 1秒 = 1000毫秒
static void sleep(long millis, int nanos) - 用于睡眠参数指定的毫秒数和纳秒数。
- 1秒 = 1000毫秒  1毫秒 = 1000微秒   1微秒 = 1000纳秒
int getPriority() - 用于获取当前线程的优先级并返回。
void setPriority(int newPriority) - 用于设置线程的优先级。
- 优先级越高表示获取到时间片的机会越多,但不一定先执行。
void join() - 用于让当前正在执行的线程等待调用join()方法的线程终止。
void join(long millis) - 用于等待参数指定的毫秒数。
void join(long millis, int nanos) - 用于等待参数指定的毫秒数+纳秒数。
boolean isDaemon() - 用于测试该线程是否为守护线程。
- 守护线程通常指后台运行为其它线程提供服务的线程,如:垃圾回收线程。
void setDaemon(boolean on) - 用于标记该线程为守护线程,必须在启动之前调用。
- 当所有非守护线程结束时,守护线程也会随之结束。

线程的同步机制(重点)

1 基本概念
当多个线程同时访问同一种共享资源时,可能会造成数据的不一致或覆盖等问题,此时就需要对多个线程进行协调,而线程之间的协调和通信就叫做线程的同步机制。

2 解决方案
由程序可知,当两个线程同时进行取款操作后,最终的账户余额与实际生活不符。
解决方案:将线程的并发操作修改为线程的串行操作。
引发问题:串行操作的效率比较低,因此以后的开发中尽量不要使用。

3 实现方式
在Java语言使用synchronized关键字来实现对象锁机制,从而保证线程操作的原子性,具体实现方式有两种:

a.使用同步语句块的方式实现,具体语法格式如下:
synchronized(对象的引用){编写所有需要锁定的代码块;
}
b.使用同步方法的方式实现,也就是使用synchronized关键字修饰整个方法即可。
该方式等价于:
synchronized(this){ 所有的方法体; }

4 实现原理(尽量理解)
当多个线程同时启动后各自独立运行去抢占共享资源,若其中一个线程抢到了共享资源,则其他线程进入阻塞状态,直到该线程执行完毕所有锁定代码后自动释放对象锁,此时阻塞的线程又可以抢占共享资源,抢到资源的线程继续加锁去执行,抢不到资源的线程继续阻塞。
以后的开发中应当尽量减少同步的范围,从而提高多个线程并发执行的效率。

死锁(尽量理解)

线程一执行的代码:
public void run(){synchronized(a){   //持有对象锁a,等待对象锁bsynchronized(b){}}
}
线程二执行的代码:
public void run(){synchronized(b){   //持有对象锁b,等待对象锁asynchronized(a){}}
}

注意:
在以后的开发中尽量不要使用同步语句块的嵌套结构!

Object类中的常用方法(尽量理解)

void wait() - 用于使得当前线程进入等待状态,直到其它线程调用notify()
或notifyAll()方法为止。
void wait(long timeout) - 使得当前线程进入等待状态,直到其它线程调用上述方法,
或者参数指定的毫秒数已经过去为止。
void notify() - 用于唤醒单个等待的线程。
void notifyAll() - 用于唤醒所有等待的线程。

线程池

网络编程

七层协议模型(了解)

ISO将数据的传递从逻辑上划分为七层来保证数据传递的可靠性和安全性等,具体如下:
应用层、表示层、会话层、传输层、网络层、数据链路层、物理层。
当发送数据时,需要按照上述七层模型从左向右依次进行加包处理,然后再发送出去。
当接收数据时,需要按照上述七层模型从右向左依次进行拆包处理,然后再解析数据。

常见的网络协议(了解)

http - 超文本传输协议,主要用于浏览网页时使用。
ftp - 文件传输协议,主要用于上传和下载文件时使用。
tcp - 传输控制协议,主要用于网络通信时使用。
udp - 用户数据报协议,主要用于网络通信时使用。
ip - 互联网协议,是互联网中的底层协议。
… …

协议 - 本质上就是一种规则/约定,约束了双方进行通信的方式。

IP地址(重点)

如:
192.168.1.1 - 是绝大多数路由器的登录地址,进行Mac地址的绑定。

IP地址 - 是设备在互联网中的唯一地址标识。
IP地址本质上是由32位二进制组成的整数,叫做IPV4,当然也有128位二进制组成的整数,叫做IPV6,目前主流的还是IPV4。
为了便于现实生活中的使用,采用点分十进制表示法来进行IP地址的描述,也就是将每个字节的二进制转换为一个十进制整数,不同的整数之间采用小数点分隔。

如:
0x01020304(十六进制) => 1.2.3.4

查看IP地址的方式:

Windows系统:在dos窗口中使用命令ipconfig或ipconfig/all查看
Linux系统:  在终端窗口中使用命令ifconfig或/sbin/ifconfig查看

端口号(重点)

IP地址 - 可以定位到具体某一台设备。
端口号 - 可以定位到该设备中的具体某个进程。
网络编程需要提供:IP地址 + 端口号。

端口号本质上是由16位二进制组成的整数,范围是:0 ~ 65535,其中0 ~ 1024之间的端口号通常被系统占用,以后的编程从1025开始使用。

基于tcp协议的编程模型(重点)

编程模型

服务器:
(1)创建ServerSocket类型的对象,并提供端口号;
(2)等待客户端的连接请求,调用accept()方法;
(3)使用输入输出流进行通信;
(4)关闭Socket并释放有关的资源;
客户端:
(1)创建Socket类型的对象,并提供服务器的IP地址和端口号;
(2)使用输入输出流进行通信;
(3)关闭Socket并释放有关的资源;

相关类和方法

ServerSocket类

java.net.ServerSocket类用于描述服务器的套接字(大插排)。
ServerSocket(int port) - 根据参数指定的端口号来创建对象。
Socket accept() - 用于监听并接受客户端的连接请求。
void close()

socket类

java.net.Socket类用于描述客户端套接字(小插排),该套接字是两台设备间通信的端点。
Socket(String host, int port) - 根据参数指定的IP地址和端口号来创建对象并建立连接
InputStream getInputStream() - 用于获取当前套接字的输入流并返回。
OutputStream getOutputStream() - 用于获取当前套接字的输出流并返回。
void close()

tcp协议和udp协议的比较(笔试题)

**tcp协议 **

  • 传输控制协议,是一种面向连接的协议,类似于打电话。
  • 建立连接 => 进行通信 => 断开连接
  • 在整个通信的过程中全程保持连接
  • 保证了数据传输的可靠性和有序性
  • 是一种全双工的字节流通信方式
  • 服务器压力比较大,资源消耗比较多,并且发送数据的效率相对比较低

udp协议

  • 用户数据报协议,是一种非面向连接的协议,类似于写信。
  • 在通信的整个过程中不需要保持连接
  • 不保证数据传输的可靠性和有序性
  • 是一种全双工的数据报通信方式
  • 服务器压力比较小,资源消耗比较少,并且发送数据的效率相对比较高。
    基于udp协议的编程模型

基于UDP协议的编程模型

主机A(接收方):
(1)创建DatagramSocket类型的对象,并提供端口号;
(2)创建DatagramPacket类型的对象,并指定缓冲区和缓冲区的大小;
(3)从Socket中接收数据放入Packet中,调用receive()方法;
(4)关闭Socket并释放有关的资源;
主机B(发送方):
(1)创建DatagramSocket类型的对象;
(2)创建DatagramPacket类型的对象,并提供接收方的IP地址和端口号;
(3)将Packet发送到Socket中,调用send()方法;
(4)关闭Socket并释放有关的资源;

DatagramSocket类

java.net.DatagramSocket类用于描述发送或接受数据报的套接字;
DatagramSocket() - 使用无参方式构造对象;
DatagramSocket(int port) - 根据参数指定的端口号来构造对象;
void receive(DatagramPacket p) - 用于接收数据并存放到参数指定的对象中;
void send(DatagramPacket p) - 用于将参数指定对象的内容发送出去;
void close()

DatagramPacket类

java.net.DatagramPacket类用于描述数据报信息;
DatagramPacket(byte[] buf, int length) - 构造对象用于接收数据;
DatagramPacket(byte[] buf, int length, InetAddress address, int port)
- 构造对象用于发送数据,并指定接收方信息;
InetAddress getAddress() - 用于获取接收方或发送方的通信地址;
int getPort() - 用于获取接收方或发送方的端口信息;
int getLength() - 用于获取数据的长度;

InetAddress类

java.net.InetAddress类用于描述通信地址;
static InetAddress getLocalHost() - 用于获取当前主机的通信地址;
static InetAddress getByName(String host) - 用于获取参数指定主机名的通信地址;
String getHostName() - 用于获取通信地址中的主机名信息;
String getHostAddress() - 用于获取通信地址中的IP地址信息;

反射机制


如:
Person p = new Person(); - 表示声明Person类型的引用指向Person类型的对象
p.show(); - 表示使用引用p调用show()方法

概念

通常情况下,编写的代码都是固定的,此时在运行阶段只能创建指定的对象和调用指定的方法,若希望在编译阶段不确定创建什么类型的对象以及调用什么样的方法,通过运行阶段传入的参数来确定,这种机制叫做动态编程/反射机制。
反射机制就是用于实现动态创建对象和动态调用方法的技术,目前主流的框架技术底层原理都是使用反射机制。

Class类

基本概念
java.lang.Class类的实例主要用于描述Java应用程序中的类和接口,也就是说该类的实例不再是表示堆区的一块空间,而是表示一种数据类型。
该类没有公共构造方法,该类的所有对象由Java虚拟机和类加载器自动构造。

获取Class对象的主要方式

a.使用数据类型.class的方式可以获取该类型的Class对象;
b.使用对象.getClass()的方式可以获取该类型的Class对象;
c.使用包装类.TYPE的方式可以获取对应基本数据类型的Class对象;
d.使用Class.forName()的方式可以获取指定类型的Class对象;

####常用的方法 ####

static Class<?> forName(String className)
- 用于获取参数指定类型的Class对象并返回;
T newInstance() - 用于创建此Class对象所表示的类对应的新实例;
如:
Class c1 = Class.forName("xdl.day21.Person");
c1.newInstance();
=> new Person();Constructor<T> getConstructor(Class<?>... parameterTypes)
- 用于获取当前Class对象所表示类中参数指定的单个公共构造方法并返回。
Constructor<?>[] getConstructors()
- 用于获取当前Class对象所表示类中所有公共构造方法并返回。
如:
Constructor ct1 = c1.getConstructor(String.class, int.class);
=> 相当于获取Person类中参数为String类型和int类型的构造方法
=> 也就是获取Person类中的有参构造并返回Field getDeclaredField(String name)
- 用于获取当前Class对象所表示类中参数指定的单个成员变量并返回。
Field[] getDeclaredFields()
- 用于获取当前Class对象所表示类中所有的成员变量并返回。
如:
Field f1 = c1.getDeclaredField("name");
=> 相当于获取Person类中名字为name的成员变量并返回。   Method getMethod(String name, Class<?>... parameterTypes)
- 用于获取当前Class对象所表示类中参数指定的单个公共成员方法并返回。
Method[] getMethods()
- 用于获取当前Class对象所表示类中所有的公共成员方法并返回。
如:
Method m1 = c1.getMethod("getName");
=> 相当于获取Person类中名字为getName的成员方法并返回。

Constructor类

基本概念
java.lang.reflect.Constructor类主要用于描述获取到的构造方法信息。

常用的方法

T newInstance(Object... initargs)
- 使用调用对象所表示的构造方法来创建新实例,并使用参数来初始化该实例。
如:
Object obj = ct1.newInstance("zhangfei", 30);
=> new Person("zhangfei", 30);

Field类

基本概念
java.lang.reflect.Field类用于描述获取到的单个成员变量信息。

常用的方法

Object get(Object obj)
- 用于返回指定对象obj中当前调用对象所表示成员变量的数值
如:
f1.get(obj);
=> 相当于获取对象obj中名字为name成员变量的数值并返回。
=> 返回obj.name的效果,也就是返回zhangfei。void set(Object obj, Object value)
- 用于将对象obj中当前调用对象所表示成员变量的数值修改为value。
如:
f1.set(obj, "guanyu");
=> 相当于将对象obj中名字为name成员变量的数值修改为guanyu。
=> 将zhangfei改为guanyu。void setAccessible(boolean flag)
- 当实参为true时表示取消Java语言的访问检查。

Method类

基本概念
java.lang.reflect.Method类用于描述获取到的单个成员方法。

常用的方法

Object invoke(Object obj, Object... args)
- 使用对象obj来调用当前调用对象所表示的成员方法,其中args为该方法的实参。
如:
m1.invoke(obj);
=> 相当于使用对象obj来调用getName()成员方法。
=> 相当于obj.getName()

设计原则

项目开发的流程

需求分析文档 => 概要设计文档 => 详细设计文档 => 编码和测试 => 安装和调试
=> 维护和升级

常用的设计原则

开闭原则

  • 对扩展开放,对修改关闭

  • 任何软件都是有bug的,bug就是臭虫、漏洞的意思

  • 提高了项目的可维护性和可扩展性。

    如:
    public class Person{
    private String name;
    private int age;
    … …
    }
    public class Student extends Person{
    private int id;
    … …
    }

里氏代换原则

  • 任何父类可以出现的地方子类一定可以出现

  • 子类 is a 父类。

  • 建议多使用继承和多态的方式编码。

    如:
    public static void draw(Shape s){
    s.show();
    }

    draw(new Rect(1, 2, 3, 4));
    draw(new Circle(5, 6, 7));

依赖倒转原则

  • 尽量多依赖抽象类和接口,而不是具体实现类

  • 抽象类和接口对子类具有强制性和规范性。

    如:
    public abstract class A{
    public abstract void show();
    }
    public class B extends A{
    public void show(){}
    }

接口隔离原则

  • 尽量多依赖于小接口而不是大接口,避免接口的污染

    如:
    public interface FlyAnimal{
    public abstract void fly();
    }
    public interface RunAnimal{
    public abstract void run();
    }
    class Dog implements RunAnimal{
    … …
    }

迪米特法则(最少知道原则)

  • 一个实体应当尽量少与其它实体之间发生关联
  • 高内聚低耦合
  • 内聚就是指一个实体应当将该有的所有功能聚集于该实体的内部。
  • 耦合就是指一个实体与其它实体之间的关联度。

合成复用原则

  • 尽量多使用合成的方式而不是继承

    如:
    class A{
    void show(){}
    }
    class B extends A{
    void test(){
    show();
    }
    }
    class A{
    void show(){}
    }
    class B{
    private A a;
    void test(){
    a.show();
    }
    }

设计模式

基本概念

设计模式(Design pattern)是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。
设计模式本质上就是一种固定的套路,使用在固定的场合中。
###基本分类 ###
创建型模式 - 工厂方法模式、抽象工厂模式、单例设计模式。(要求会写)
结构型模式 - 装饰器模式、代理模式。(要求看懂)
行为型模式 - 模板设计模式、观察者模式。(以后讲到)
常用的算法

常用的查找算法(重点)

线性查找算法(顺序查找算法)

算法流程

a.使用目标元素与样本数列中的第一个元素起依次进行比较;
b.若找到与目标元素相等的元素,则表示查找成功;
c.若目标元素与所有样本元素比较完毕都没有找到相等的元素,则表示查找失败;

二分查找算法(折半查找算法)

算法流程

a.假定样本数列从小到大排列,使用目标元素与样本数列中的中间元素比较大小;
b.若目标元素与中间元素相等,则表示查找成功;
c.若目标元素小于中间元素,则应该去中间元素的左边进行查找,重复步骤b;
d.若目标元素大于中间元素,则应该去中间元素的右边进行查找,重复步骤b;
e.直到目标元素与所有该比较的元素比较完毕也不相等,则表示查找失败;

常用的排序算法

冒泡排序算法(重中之重)

算法流程

a.比较相邻位置两个元素的大小,若第一个元素比第二个元素大,则交换两个元素的位置;
b.从开始的第一对元素一直到结尾的最后一对,使用步骤1依次比较,经过这一轮,最后的
元素将是这组元素中的最大值;
c.重复步骤b,持续对越来越少的元素进行比较,直到处理完毕所有元素为止;
(当任意两个相邻位置的元素都不需要发生交换时,证明排序完毕)

插入排序算法(理解思想)

算法流程

a.从第一个元素起,认定该元素已经有序;
b.取出下一个元素,让取出的元素与左边的有序数列从右向左依次比较大小;
c.若取出的元素小于左边的元素,则将左边的元素右移,也就是赋值到下一个位置;
d.若取出的元素大于等于左边的元素,则将取出的元素插入到左边元素的右边;
e.重复步骤b,直到处理完毕所有元素为止;

选择排序算法(理解思想)

算法流程

a.取出第一个元素,并假定该元素为这组元素中的最小值,使用变量min记录下标;
b.使用min记录的最小值与后续元素依次比较大小;
c.若后续元素中出现了比min记录的最小值还小的元素,则使用min重新记录该元素;
d.直到min记录的最小值与后续所有元素比较完毕时,交换min记录的最小值与最开始
假定的最小值,经过这一步,这组元素中的最小值便放在了最起始位置;
e.重复步骤a,直到处理完毕所有元素为止;

快速排序算法(重点)

算法流程

a.使用样本数列中的中间元素作为基准值并单独保存;
b.分别使用左右两边的元素依次与基准值比较大小,将所有比基准值小的元素放在基准值
的左边,将所有大于等于基准值的元素放到基准值的右边,这个过程叫做分组;
c.直到左右两边的元素下标重合时,将基准值放到重合的位置,此时分组完成;
d.分别对基准值左右两边的分组重复以上过程进行再次分组,直到处理完毕所有元素为止;

SE阶段代表性编程题

1.打印九九乘法表(双重for循环)
2.个人所得税(if else if 分支结构)
3.数组的增删改查
4.递归方法的调用
5.单例设计模式(饿汉式,懒汉式)
6.匿名内部类
7.自定义异常类
8.递归实现多层文件读取文件名
9.使用byte[] 实现文件的拷贝
10.多线程的实现方式(扩展)
11.基于TCP协议的网络编程(UDP协议 扩展)
12.冒泡算法(快速算法 扩展)
13.工厂模式 抽象工程模式(23种设计模式 扩展)
14.学生信息管理系统

那年学过的Java笔记三核心类库三相关推荐

  1. 那年学过的Java笔记三核心类库一

    核心类库一: 抽象类 抽象方法的概念 抽象方法就是指不能具体实现的方法,也就是该方法没有方法体,使用abstract关键字修饰 具体语法格式如下: 访问控制符 abstract 返回值类型 方法名称( ...

  2. 那年学过的Java笔记三核心类库二

    集合类 数组和集合的比较 数组的特点: 本质上就是一段连续的存储空间,用于记录多个类型相同的数据. 支持下标访问,可以实现随机访问. 数组一旦定义则长度固定,无法自动调整内存空间的大小. 增删元素不方 ...

  3. 那年学过的Java笔记一SE基础

    JavaSE知识点梳理 [外链图片转存失败(img-EbT2nyO4-1564412078255)(https://i.imgur.com/eZoqsaL.jpg)] JavaSE基础 [外链图片转存 ...

  4. 那年学过的Java笔记二SE面向对象

    面向对象 面向对象编程 1 什么是对象? 万物皆对象. 2 什么是面向对象? 面向对象就是指以特征/属性和行为的观点去分析现实世界中事物的方式.3 什么是面向对象编程? 面向对象编程就是指先以面向对象 ...

  5. Java笔记04-核心类库

    Java笔记04-核心类库 Object类 1.1 常用的包 java.lang包 -该包是Java语言中的核心包,该包中的内容由Java虚拟机自动导入 如:String类,System类等java. ...

  6. java aio socket_java核心学习(三十三) 网络编程---AIO实现异步Socket通信

    AIO需要操作系统的支持,在linux内核2.6版本中加入了对真正异步IO的支持,java从jdk1.7开始支持AIO 核心类有AsynchronousSocketChannel .Asynchron ...

  7. 小汤学编程之JAVA基础day08——面向对象(三):抽象类与接口

    一.抽象类 1.抽象类的由来      2.几点注意     3.语法规则 二.接口 1.定义方式      2.属性和方法 三.总结 一.抽象类 1.抽象类的由来 "用进废退", ...

  8. 那年学过的Oracle笔记

    数据库基础 DB 数据库(Database)是按照数据结构来组织.存储和管理数据的建立在计算机存储设备上的仓库. 简单来说是本身可视为电子化的文件柜--存储电子文件的处所,用户可以对文件中的数据进行新 ...

  9. Java基础测试题 - 核心类库(二)

    1. 进程和线程有什么区别? 进程:是指一个内存中运行的应用程序,每个进程都有一个独立的内存空间: 线程: 是进程中的一个执行路径,共享一个内存空间,线程之间可以自由切换,并发执行,一个进程最少有一个 ...

最新文章

  1. RDS读写分离,海量数据一键搞定
  2. 超越YOLOv5,1.3M超轻量,高效易用,目标检测领域这一个就够了!
  3. zoj 3620 Escape Time II
  4. SX-BOX试用笔记
  5. python 图片读写_Python各种图像库的图像的基本读写方式
  6. omcat 7 的domain域名配置,Tomcat 修改JSESSIONID
  7. Linux 安装flash
  8. 教你如何更好的用ubuntu
  9. 计算机九宫格游戏怎么玩,《九宫格数独》怎么玩 数独玩法介绍
  10. 安装卸载Windows服务方法(2种方法)
  11. revit2019 导出obj_Revit导出OBJ格式
  12. JavaWeb报错500 类错误 解决方法
  13. 秒懂Https之CA证书与自签名证书漫谈
  14. 在弱肉强食的世界里,人类的美德意识为何能够超越其他物种?
  15. Python+Vue计算机毕业设计餐饮管理系统qpa33(源码+程序+LW+部署)
  16. prompt learning
  17. 毕业论文的奋斗记(一)
  18. GBF ASIA亚太电池展
  19. Exception 异常
  20. 平头哥玄铁CPU调试系统介绍

热门文章

  1. 你用python做过哪些好玩的事情?
  2. 解决miner.start() 返回null
  3. flow使用_使用Microsoft Flow进行文本分析
  4. 《梦断代码》读后感03——为什么我们不能像造桥一样造软件
  5. linux free命令详解(一)
  6. linux-tomcat连接数查询
  7. 洛谷3396 哈希冲突 【分块】
  8. HDU1813:Escape from Tetris(IDA)
  9. Linux 系统使用之 VMware Tools安装
  10. 数据库软件dbForge Studio for MySQL更新至v.6.1