参考:php
基本数据类型 | 字节 | 范围 | 默认值 | |
---|---|---|---|---|
byte | 8-bit 1个字节 | -128 ~ 127 | 0 | |
short | 16-bit 2个字节 | -32768 ~ 32767 | 0 | |
int | 32-bit 4个字节 | -2^31 ~ 2^31 - 1 | 0 | |
long | 64-bit 8个字节 | -2^63 ~ 2^63 -1 | 0L | |
float | 32-bit 4个字节 | 0.0f | ||
double | 64-bit 8个字节 | 0.0d | ||
boolean | 1-bit | false | ||
char | 16-bit unicode字符 | '\u0000'~'\uffff' | '\u0000' |
char = '中文'
能够经过编译么?能够。html
public class primitivetype {
public static void main(String[] args) {
char i = '中';
System.out.println(i);
}
}
复制代码
能够运行输出'中'前端
Java中的一个char采用的是Unicode编码集,占用两个字节,而一个中文字符也是两个字节,所以Java中的char是能够表示一个中文字符的。java
可是在C/C++中因为采用的字符编码集是ASCII,只有一个字节,所以是没办法表示一个中文字符的。node
Java中的char是否能够存储一个中文字符之理解字符字节以及编码集mysql
java中char类型固定占2个字节。(注:char类型也能够存储一个汉字)。web
以utf8为例,utf8是一个变长编码标准,能够以1~4个字节表示一个字符,而中文占3个字节,ascII字符占1个字节。算法
那么为何咱们在java里面能够用一个char来表示一个中文呢?spring
由于java是以unicode做为编码方式的。unicode是一个定长的编码标准,每一个字符都是2个字节,也就是1个char类型的空间。sql
在编译时会把utf8的中文字符转换成对应的unicode来进行传输运算。
String采用一种更灵活的方式进行存储。在String中,一个英文字符占1个字节,而中文字符根据编码的不一样所占字节数也不一样。在UTF-8编码下,一个中文字符占3个字节;而使用GBK编码时一个中文字符占2个字节。测试代码以下
中文并不必定是占两个字节的,具体占多少字节是跟具体的编码方式相关的。 好比说:GB23十二、GBK、GB18030 编码是占用两个字节的,可是 UTF-8 编码的话至少须要占用三个字节。
MVC模式是软件工程中的一种软件架构模式,把软件系统分为三个基本部分:模型、视图和控制器。
mvc是一种建构网站的方法或思想,设计理念。mvc不是框架,而框架是基于mvc思想。
在早期java web,主要使用jsp + java bean模式,jsp与java bean产生严重耦合。出现了前端后端相互依赖的问题。
因而出现了servlet + jsp + java bean。 servlet是controller jsp是view 各自java bean 是model 对于后端来讲,因为控制器和模型层的分离使得许多代码能够重用。 mvc的经典框架 struts1/struts2和做为模型层的hibernate纷纷出现。
执行原理
假如输入maps.google.com
dns:domain name system 保存域名和链接的ip地址,每个url都有惟一的ip地址。
为了找到dns记录,浏览器会依次检查如下4种缓存
Internet Service Provider,簡稱ISP
为了让个人计算机链接到托管maps.google.com的服务器,我须要maps.google.com的IP地址。DNS查询的目的是在internet上搜索多个DNS服务器,直到找到网站的正确IP地址。这种类型的搜索被称为递归搜索,由于搜索将在DNS服务器和DNS服务器之间重复进行,直到找到咱们须要的IP地址,或者返回一个错误响应说没法找到它为止。
在这种状况下,咱们将把ISP的DNS服务器称为DNS递归器,它的职责是经过询问internet上的其余DNS服务器来找到想要的域名的正确IP地址。其余DNS服务器称为名称服务器,由于它们基于网站域名的域架构执行DNS搜索。
HTTP协议即超文本传送协议(Hypertext Transfer Protocol ),是Web联网的基础,也是手机联网经常使用的协议之一,HTTP协议是创建在TCP协议之上的一种应用。
一旦浏览器接收到正确的IP地址,它将与匹配IP地址以传输信息的服务器创建TCP链接。三次握手。
为了在您的计算机(客户端)和服务器之间传输数据包,创建一个TCP链接很是重要。这个链接是经过一个叫作TCP/IP三方握手的过程创建的。这是一个三个步骤,其中客户端和服务器交换SYN(同步)和ACK(确认)消息来创建链接。
为了保证服务端能收接受到客户端的信息并能作出正确的应答而进行前两次(第一次和第二次)握手,为了保证客户端可以接收到服务端的信息并能作出正确的应答而进行后两次(第二次和第三次)握手。
好比get请求 localhost:8080
Host: localhost:8080
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.13; rv:60.0) Gecko/20100101 Firefox/60.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Cookie: JSESSIONID=8051806AE26B8CAB93BA03AC32A2191E; JSESSIONID=63AB1FE24ECF5F0930743468B802818B
Connection: keep-alive
Upgrade-Insecure-Requests: 1
Cache-Control: max-age=0
复制代码
该服务器包含一个web服务器(好比apache)。接收来自浏览器的请求并将其传递给请求处理程序以读取和生成响应。请求处理程序是一个程序(用php等编写)用于读取请求、其头部和cookies,以检查所请求的内容,并在须要时更新服务器上的信息。而后它将以特定的格式(JSON、XML、HTML)组装响应。
服务器响应包含您请求的web页面、状态代码、压缩类型(内容编码)、如何缓存页面(缓存控制)、要设置的任何cookie、隐私信息等。
HTTP/1.1 200
Content-Type: text/html;charset=UTF-8
Content-Language: zh-CN
Content-Length: 97
Date: Wed, 04 Jul 2018 08:04:54 GMT
复制代码
状态码:
浏览器分阶段显示HTML内容。首先,它将呈现裸骨HTML骨架。而后,它将检查HTML标记并发出GET请求,请求web页面上的其余元素,如图像、CSS样式表、JavaScript文件等。这些静态文件被浏览器缓存,这样下次访问页面时就没必要再取回它们了。最后,你会看到网页出如今你的浏览器上。
hashmap是基于哈希表即散列表的。
hashmap经过hashCode方法计算hash值,hash值是经过key对象来计算。hash值用来找到存储Entry的正确位置。
hashmap使用equals方法来查找在get()时要检索的键的值,并在put()时查找该键是否已经存在。
冲突意味着有多个键拥有一样的hash值,在这种状况下entry对象将会存储在了同一个linkedlist里。
HashMap在java中使用内部 Node<K,V>来存储映射。HashMap基于散列算法,并在键上使用hashCode()和equals()方法进行get和put操做。
HashMap使用单个链表来存储元素,这些元素称为bucket。当咱们调用put方法时,将使用key的hashCode来肯定存储映射的bucket。
一旦肯定了bucket,就使用hashCode检查是否已经有一个具备相同hashCode的键。若是存在一个具备相同hashCode的现有键,则在key上使用equals()方法。若是equals返回true,那么value将被覆盖,不然将对这个单独连接的list bucket建立一个新的映射。若是没有具备相同hashCode的键,则将映射插入到bucket中。
hashmap 有一个表
**
* The table, resized as necessary. Length MUST Always be a power of two.
*/
transient Node<K,V>[] table;
复制代码
static class Node<K,V> implements Map.Entry<K,V> {
final int hash;
final K key;
V value;
Node<K,V> next;
Node(int hash, K key, V value, Node<K,V> next) {
this.hash = hash;
this.key = key;
this.value = value;
this.next = next;
}
public final K getKey() { return key; }
public final V getValue() { return value; }
public final String toString() { return key + "=" + value; }
public final int hashCode() {
return Objects.hashCode(key) ^ Objects.hashCode(value);
}
public final V setValue(V newValue) {
V oldValue = value;
value = newValue;
return oldValue;
}
public final boolean equals(Object o) {
if (o == this)
return true;
if (o instanceof Map.Entry) {
Map.Entry<?,?> e = (Map.Entry<?,?>)o;
if (Objects.equals(key, e.getKey()) &&
Objects.equals(value, e.getValue()))
return true;
}
return false;
}
}
复制代码
put方法,注意链表中是红黑树的实现
TreeNode节点,这个类有很是多的方法
static final class TreeNode<K,V> extends LinkedHashMap.Entry<K,V> {
TreeNode<K,V> parent; // red-black tree links
TreeNode<K,V> left;
TreeNode<K,V> right;
TreeNode<K,V> prev; // needed to unlink next upon deletion
boolean red;
TreeNode(int hash, K key, V val, Node<K,V> next) {
super(hash, key, val, next);
}
}
复制代码
public V put(K key, V value) {
return putVal(hash(key), key, value, false, true);
}
/** * Implements Map.put and related methods * * @param hash hash for key * @param key the key * @param value the value to put * @param onlyIfAbsent if true, don't change existing value * @param evict if false, the table is in creation mode. * @return previous value, or null if none */
final V putVal(int hash, K key, V value, boolean onlyIfAbsent, boolean evict) {
Node<K,V>[] tab; Node<K,V> p; int n, i;
if ((tab = table) == null || (n = tab.length) == 0)
n = (tab = resize()).length;
if ((p = tab[i = (n - 1) & hash]) == null)
tab[i] = newNode(hash, key, value, null);
else {
Node<K,V> e; K k;
if (p.hash == hash &&
((k = p.key) == key || (key != null && key.equals(k))))
e = p;
else if (p instanceof TreeNode)
e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
else {
for (int binCount = 0; ; ++binCount) {
if ((e = p.next) == null) {
p.next = newNode(hash, key, value, null);
if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
treeifyBin(tab, hash);
break;
}
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k))))
break;
p = e;
}
}
if (e != null) { // existing mapping for key
V oldValue = e.value;
if (!onlyIfAbsent || oldValue == null)
e.value = value;
afterNodeAccess(e);
return oldValue;
}
}
++modCount;
if (++size > threshold)
resize();
afterNodeInsertion(evict);
return null;
}
复制代码
gc须要完成的3件事情
- 何时回收?
- 哪些内存须要回收?
- 如何回收?
对堆进行回收以前首先要肯定对象之中哪些还“存活”,哪些“死去”。
引用计数算法
可达性分析算法 这个算法的基本思路就是经过一系列的称为“GC Roots”的对象做为起始点,从这些节点开始向下搜索,搜索所走过的路径称为引用链(Reference Chain),当一个对象到GC Roots没有任何引用链相连(用图论的话来讲,就是从GC Roots到这个对象不可达)时,则证实此对象是不可用的。
在java中,可做为GC Roots的对象包括如下几种:
Object obj=new Object()
这类的引用,只要强引用还存在,垃圾收集器永远不会回收掉被引用的对象。永久代的垃圾回收主要回收两部分
最基础的收集算法,"mark-sweep"标记-清除算法。
算法分为“标记”和“清除”两个阶段:首先标记出全部须要回收的对象,在标记完成后统一回收全部被标记的对象,它的标记过程其实在前一节讲述对象标记断定时已经介绍过了。之因此说它是最基础的收集算法,是由于后续的收集算法都是基于这种思路并对其不足进行改进而获得的。
它的主要不足有两个:一个是效率问题,标记和清除两个过程的效率都不高;另外一个是空间问题,标记清除以后会产生大量不连续的内存碎片,空间碎片太多可能会致使之后在程序运行过程当中须要分配较大对象时,没法找到足够的连续内存而不得不提早触发另外一次垃圾收集动做。
为了解决效率问题,一种称为“复制”(Copying)的收集算法出现了,它将可用内存按容量划分为大小相等的两块,每次只使用其中的一块。当这一块的内存用完了,就将还存活着的对象复制到另一块上面,而后再把已使用过的内存空间一次清理掉。这样使得每次都是对整个半区进行内存回收,内存分配时也就不用考虑内存碎片等复杂状况,只要移动堆顶指针,按顺序分配内存便可,实现简单,运行高效。只是这种算法的代价是将内存缩小为了原来的一半,未免过高了一点。
新生代中的对象98%是“朝生夕死”的,因此并不须要按照1:1的比例来划份内存空间,而是将内存分为一块较大的Eden空间和两块较小的Survivor空间,每次使用Eden和其中一块Survivor。当回收时,将Eden和Survivor中还存活着的对象一次性地复制到另一块Survivor空间上,最后清理掉Eden和刚才用过的Survivor空间。HotSpot虚拟机默认Eden和Survivor的大小比例是8:1,也就是每次新生代中可用内存空间为整个新生代容量的90%(80%+10%),只有10%的内存会被“浪费”。固然,98%的对象可回收只是通常场景下的数据,咱们没有办法保证每次回收都只有很少于10%的对象存活,当Survivor空间不够用时,须要依赖其余内存(这里指老年代)进行分配担保(Handle Promotion)。
标记过程仍然与“标记-清除”算法同样,但后续步骤不是直接对可回收对象进行清理,而是让全部存活的对象都向一端移动,而后直接清理掉端边界之外的内存。
只是根据对象存活周期的不一样将内存划分为几块。通常是把Java堆分为新生代和老年代,这样就能够根据各个年代的特色采用最适当的收集算法。
在新生代中,每次垃圾收集时都发现有大批对象死去,只有少许存活,那就选用复制算法,只须要付出少许存活对象的复制成本就能够完成收集。
而老年代中由于对象存活率高、没有额外空间对它进行分配担保,就必须使用“标记—清理”或者“标记—整理”算法来进行回收。
若是说收集算法是内存回收的方法论,那么垃圾收集器就是内存回收的具体实现
eden满了minor gc,升到老年代的对象大于老年代剩余空间full gc,或者小于时被HandlePromotionFailure参数强制full gc;gc与非gc时间耗时超过了GCTimeRatio的限制引起OOM,调优诸如经过NewRatio控制新生代老年代比例,经过MaxTenuringThreshold控制进入老年前生存次数等
参考:icyfenix.iteye.com/blog/715301
慢sql特色 1 数据库CPU负载高。通常是查询语句中有不少计算逻辑,致使数据库cpu负载。 2 IO负载高致使服务器卡住。这个通常和全表查询没索引有关系。 3 查询语句正常,索引正常可是仍是慢。若是表面上索引正常,可是查询慢,须要看看是否索引没有生效。
打开MySQL的慢查询日志来进一步定位问题。mysql提供了慢查询日志,日志会记录全部执行时间超过long_query_time的sql
要开启日志,须要在MySQL的配置文件的mysqlld项下配置慢查询日志开启。
有些SQL虽然出如今慢查询日志中,但未必是其自己的性能问题,多是由于锁等待,服务器压力高等等。
须要分析SQL语句真实的执行计划,而不是看从新执行一遍SQL时,花费了多少时间,由自带的慢查询日志或者开源的慢查询系统定位到具体的出问题的SQL,而后使用Explain工具来逐步调优,了解 MySQL 在执行这条数据时的一些细节,好比是否进行了优化、是否使用了索引等等。基于 Explain 的返回结果咱们就能够根据 MySQL 的执行细节进一步分析是否应该优化搜索、怎样优化索引。
两个表,customers,orders
customers
cust_id | cust_name | cust_address | cust_city | cust_state | cust_zip | cust_country | cust_contact | cust_email | |
---|---|---|---|---|---|---|---|---|---|
10001 | Coyote Inc. | 200 Maple Lane | Detroit | MI | 44444 | USA | Y Lee | ylee@coyote.com | |
10002 | Mouse House | 333 Fromage Lane | Columbus | OH | 43333 | USA | Jerry Mouse | NULL | |
10003 | Wascals | 1 Sunny Place | Muncie | IN | 42222 | USA | Jim Jones | rabbit@wascally.com | |
10004 | Yosemite Place | 829 Riverside Drive | Phoenix | AZ | 88888 | USA | Y Sam | sam@yosemite.com | |
10005 | E Fudd | 4545 53rd Street | Chicago | IL | 54545 | USA | E Fudd | NULL |
内部联结
orders
order_num | order_date | cust_id |
---|---|---|
20005 | 2005-09-01 00:00:00 | 10001 |
20006 | 2005-09-12 00:00:00 | 10003 |
20007 | 2005-09-30 00:00:00 | 10004 |
20008 | 2005-10-03 00:00:00 | 10005 |
20009 | 2005-10-08 00:00:00 | 10001 |
SELECT customers.cust_id,orders.order_num FROM customers INNER JOIN orders ON customers.cust_id = orders.cust_id;
复制代码
cust_id | order_num |
---|---|
10001 | 20005 |
10001 | 20009 |
10003 | 20006 |
10004 | 20007 |
10005 | 20008 |
外部联结
SELECT customers.cust_id,orders.order_num FROM customers LEFT OUTER JOIN orders ON customers.cust_id = orders.cust_id
复制代码
cust_id | order_num |
---|---|
10001 | 20005 |
10001 | 20009 |
10002 | NULL |
10003 | 20006 |
10004 | 20007 |
10005 | 20008 |
SELECT customers.cust_id,orders.order_num FROM customers RIGHT OUTER JOIN orders ON customers.cust_id = orders.cust_id
复制代码
cust_id | order_num |
---|---|
10001 | 20005 |
10001 | 20009 |
10003 | 20006 |
10004 | 20007 |
10005 | 20008 |
在使用OUTER JOIN
语法时,必须使用RIGHT
或LEFT
关键字 指定包括其全部行的表(RIGHT
指出的是OUTER JOIN
右边的表,而LEFT
指出的是OUTER JOIN
左边的表)。上面的例子使用LEFT OUTER JOIN
从FROM
子句的左边表(customers表)中选择全部行。为了从右边的表中选择全部行,应该使用RIGHT OUTER JOIN
.
当表的数据量比较大时,查询操做会比较耗时。创建索引是加快查询速度的有效手段。数据库索引相似于图书后面的索引,能快速定位到须要查询的内容。
数据库索引有多种类型,常见索引包括顺序文件上的索引
,b+树索引
、哈希索引
、位图索引
、全文索引
。
在mysql中,存储引擎先在索引中找到对应值,而后根据匹配的索引记录找到对应的数据行。
mysql先在索引上按值进行查找,而后返回全部包含该值的数据行。
索引能够包含一个或多个列的值。若是索引包含多个列,那么列的顺序也十分重要,由于mysql只能高效地使用索引的最左前缀列。
索引可让服务器快速定位到表的指定位置 索引的优势:
mysql支持的数据类型很是多,选择正确的数据类型对于得到高性能相当重要。无论存储哪一种类型的数据,下面几个简单的原则都有助于做出更好选择。
索引的代价:1.须要占硬盘空间 2.一旦插入新的数据,须要从新建索引 高性能索引策略
优化数据访问
重构查询的方式
class Solution {
public List<List<Integer>> levelOrder(TreeNode root) {
List<List<Integer>> res = new ArrayList<>();
if(root == null){
return res;
}
Queue<TreeNode> qp = new LinkedList<>();
qp.offer(root);
while(!qp.isEmpty()){
List<Integer> level = new ArrayList<>();
TreeNode node = null;
int lenL = qp.size();
for(int i = 0; i < lenL; i++){
node = qp.poll();
level.add(node.val);
if(node.left != null){
qp.offer(node.left);
}
if(node.right != null){
qp.offer(node.right);
}
}
res.add(level);
}
return res;
}
}
复制代码