JAVA概述

java主要特性:

  1. java语言是简单的
    java语言不使用指针,而是引用。并提供了自动的废料收集,使得程序员不必为内存管理而担忧。
  2. java语言是面相对象的
    java语言提供类、继承、接口等面相对象的特性
  3. java语言是分布式的
  4. java语言是健壮的
    java的强类型机制、异常处理、垃圾的自动收集等是java健壮性的重要保证
  5. java语言是安全的
  6. java语言是体系结构中立的
  7. java语言是可移植的
  8. java语言是解释性的
  9. java语言是高性能的
  10. java语言是多线程的
    在Java语言中,线程是一种特殊的对象,它必须由Thread类或其子(孙)类来创建。通常有两种方法来创建线程:其一,使用型构为Thread(Runnable)的构造子将一个实现了Runnable接口的对象包装成一个线程,其二,从Thread类派生出子类并重写run方法,使用该子类创建的对象即为线程。
    Java语言支持多个线程的同时执行,并提供多线程之间的同步机制(关键字为synchronized)。
  11. java语言是动态的

java基础语法

  1. 对象:
    对象是类的一个实例,有状态和行为。

  2. 类是一个模板,他描述一类对象的状态和行为。
  3. 方法
    方法就是行为,一个类可以有很多方法。
  4. 实例变量
    每个对象都有独特的实例变量,对象的状态由这些实例变量的值决定。

java修饰符

主要有两类修饰符:
访问控制修饰符:default, public , protected, private
非访问控制修饰符:final, abstract, strictfp

  1. default (即缺省,什么也不写): 在同一包内可见,不使用任何修饰符。使用对象:类、接口、变量、方法。
  2. private : 在同一类内可见。使用对象:变量、方法。 注意:不能修饰类(外部类)
    声明为私有访问类型的变量只能通过类中公共的 getter 方法被外部类访问。
  3. public : 对所有类可见。使用对象:类、接口、变量、方法
  4. protected : 对同一包内的类和所有子类可见。使用对象:变量、方法。 注意:不能修饰类(外部类)。

访问控制和继承:

  • 父类中声明为 public 的方法在子类中也必须为 public。
  • 父类中声明为 protected 的方法在子类中要么声明为 protected,要么声明为 public,不能声明为 private。
  • 父类中声明为 private 的方法,不能够被继承。

非访问控制符:

  1. static 修饰符,用来修饰类方法和类变量。
  2. final 修饰符,用来修饰类、方法和变量,final 修饰的类不能够被继承,修饰的方法不能被继承类重新定义,修饰的变量为常量,是不可修改的。
  3. abstract 修饰符,用来创建抽象类和抽象方法。抽象类不能用来实例化对象,声明抽象类的唯一目的是为了将来对该类进行扩充。
    一个类不能同时被 abstract 和 final 修饰。如果一个类包含抽象方法,那么该类一定要声明为抽象类,否则将出现编译错误。任何继承抽象类的子类必须实现父类的所有抽象方法,除非该子类也是抽象类。
  4. synchronized 修饰符。synchronized 关键字声明的方法同一时间只能被一个线程访问。
  5. volatile 修饰符,volatile 修饰的成员变量在每次被线程访问时,都强制从共享内存中重新读取该成员变量的值。而且,当成员变量发生变化时,会强制线程将变化值回写到共享内存。这样在任何时刻,两个不同的线程总是看到某个成员变量的同一个值。
  6. transient 修饰符,序列化的对象包含被 transient 修饰的实例变量时,java 虚拟机(JVM)跳过该特定的变量。

该修饰符包含在定义变量的语句中,用来预处理类和变量的数据类型。

java变量

主要有三种类型的变量

  1. 局部变量
    在方法、构造方法或者语句块中定义的变量被称为局部变量。变量声明和初始化都是在方法中,方法结束后,变量就会自动销毁。
    访问修饰符不能用于局部变量;
    局部变量是在栈上分配的。
    局部变量没有默认值,所以局部变量被声明后,必须经过初始化,才可以使用。
  2. 类变量(静态变量)
    类变量也声明在类中,方法体之外,但必须声明为static类型。
    静态变量储存在静态存储区。经常被声明为常量,很少单独使用static声明变量。静态变量可以通过:ClassName.VariableName的方式访问。
  3. 成员变量(非静态变量)
    成员变量是定义在类中,方法体之外的变量。这种变量在创建对象的时候实例化。成员变量可以被类中方法、构造方法和特定类的语句块访问。
    实例变量具有默认值。数值型变量的默认值是0,布尔型变量的默认值是false,引用类型变量的默认值是null。变量的值可以在声明时指定,也可以在构造方法中指定;

成员变量与类变量的区别:

  1. 两个变量的生命周期不同
    成员变量随着对象的创建而存在,随着对象的回收而释放。
    静态变量随着类的加载而存在,随着类的消失而消失。
  2. 调用方式不同
    成员变量只能被对象调用。
    静态变量可以被对象调用,还可以被类名调用。
  3. 别名不同
    成员变量也称为实例变量。
    静态变量也称为类变量。
  4. 数据存储位置不同
    成员变量存储在堆内存的对象中,所以也叫对象的特有数据。
    静态变量数据存储在方法区(共享数据区)的静态区,所以也叫对象的共享数据。

特点:

  1. 想要实现对象中的共性数据的对象共享。可以将这个数据进行静态修饰。
  2. 被静态修饰的成员,可以直接被类名所调用。也就是说,静态的成员多了一种调用方式。类名.静态方式。
  3. 静态随着类的加载而加载。而且优先于对象存在。

弊端:

  1. 有些数据是对象特有的数据,是不可以被静态修饰的。因为那样的话,特有数据会变成对象的共享数据。这样对事物的描述就出了问题。所以,在定义静态时,必须要明确,这个数据是否是被对象所共享的。
  2. 静态方法只能访问静态成员,不可以访问非静态成员。
    因为静态方法加载时,优先于对象存在,所以没有办法访问对象中的成员。
  3. 静态方法中不能使用this,super关键字。
    因为this代表对象,而静态在时,有可能没有对象,所以this无法使用。

成员分两种:

  1. 成员变量。(数据共享时静态化)
    该成员变量的数据是否是所有对象都一样:
    如果是,那么该变量需要被静态修饰,因为是共享的数据。
    如果不是,那么就说这是对象的特有数据,要存储到对象中。
  2. 成员函数。(方法中没有调用特有数据时就定义成静态)
    如果判断成员函数是否需要被静态修饰呢?
    只要参考,该函数内是否访问了对象中的特有数据:
    如果有访问特有数据,那方法不能被静态修饰。
    如果没有访问过特有数据,那么这个方法需要被静态修饰。

成员变量与局部变量的区别:

  1. 声明位置不同
    成员变量也就是属性,在类中声明的。
    局部变量,在方法中声明或代码块中声明。
  2. 初始值不同
    成员变量如果没有赋值则是有默认值的,数据类型不同则默认值不同。
    局部变量是没有默认值,也就是说必须先声明,再赋值,最后才使用。
  3. 在一个类中,局部变量可以与成员变量同名,但是局部变量优先,如果非要访问成员变量的属性,则必须使用 this.color
    this 代表当前这个对象,也就是当前谁调用这个方法则这个对象就是谁。
    对象与引用区别
    对象是具体的一个实例,如:new Student(); new 表示创建一个对象,并在堆内存中开辟一块空间。
    引用名称是存放的对象的地址。

构造方法

每个类都有构造方法。如果没有显式地为类定义构造方法,Java编译器将会为该类提供一个默认构造方法。
在创建一个对象的时候,至少要调用一个构造方法。构造方法的名称必须与类同名,一个类可以有多个构造方法。

源文件声明规则

  1. 一个源文件中只能有一个public类
  2. 一个源文件可以有多个非public类
  3. 源文件的名称应该和public类的类名保持一致。
  4. 如果一个类定义在某个包中,那么package语句应该在源文件的首行。
  5. 如果源文件包含import语句,那么应该放在package语句和类定义之间。如果没有package语句,那么import语句应该在源文件中最前面。
  6. import语句和package语句对源文件中定义的所有类都有效。在同一源文件中,不能给不同的类不同的包声明。

java基本数据类型

变量就是申请内存来存储值。也就是说,当创建变量的时候,需要在内存中申请空间。
内存管理系统根据变量的类型为变量分配存储空间,分配的空间只能用来储存该类型数据。

java的两大数据类型:

  1. 内置数据类型
  2. 引用数据类型

内置数据类型:

类型 默认值 包装类 备注
byte 0 java.lang.Byte Byte.SIZE Byte.MIN_VALUE Byte.MAX_VALUE
short 0 java.lang.Short Short.SIZE Short.MIN_VALUE Short.MAX_VALUE
int 0 java.lang.Integer Integer.SIZE Integer.MIN_VALUE Integer.MAX_VALUE
long 0L java.lang.Long Long.SIZE Long.MIN_VALUE Long.MAX_VALUE
float 0.0f java.lang.Float Float.SIZE Float.MIN_VALUE Float.MAX_VALUE
double 0.0d java.lang.Double Double.SIZE Double.MIN_VALUE Double.MAX_VALUE
boolean false
char java.lang.Character Character.SIZE Character.MIN_VALUE Character.MAX_VALUE

自动类型转换:
必须满足转换前的数据类型的位数要低于转换后的数据类型
byte,short,char—> int —> long—> float —> double
char c1='a';//定义一个char类型
int i1 = c1;//char自动类型转换为int

强制类型转换:
在把容量大的类型转换为容量小的类型时必须使用强制类型转换。
转换过程中可能导致溢出或损失精度。
格式:(type)value type是要强制类型转换后的数据类型
int i1 = 123;
byte b = (byte)i1;//强制类型转换为byte

引用类型:
所有引用类型的默认值都是null。

类型转换的方法:

  1. 一般情况下,我们首先声明一个变量,然后生成一个对应的包装类,就可以利用包装类的各种方法进行类型转换了。
    当希望把float型转换为double型时:
float f1=100.00f;
Float F1=new Float(f1);//Boolean(boolean value)、Character(char value)、Integer(int value)、Long(long value)、Float(float value)、Double(double value)
double d1=F1.doubleValue();//F1.doubleValue()为Float类的返回double值型的方法
  1. 其它类型向字符串的转换
  • 调用类的串转换方法:X.toString();
  • 自动转换:X+"";
  • 使用String的方法:String.valueOf(X);
  1. 字符串作为值,向其它类型的转换
  • 先转换成相应的封装器实例,再调用对应的方法转换成其它类型
    例如,字符中"32.1"转换double型的值的格式为:new Float("32.1").doubleValue()。也可以用:Double.valueOf("32.1").doubleValue()
  • 静态parseXXX方法
String s = "1";
byte b = Byte.parseByte( s );
short t = Short.parseShort( s );
int i = Integer.parseInt( s );
long l = Long.parseLong( s );
Float f = Float.parseFloat( s );
Double d = Double.parseDouble( s );
  1. Date类与其它数据类型的相互转换
import java.text.SimpleDateFormat;

java.util.Date date = new java.util.Date();
//如果希望得到YYYYMMDD的格式
SimpleDateFormat sy1=new SimpleDateFormat("yyyyMMdd");
String dateFormat=sy1.format(date);
//如果希望分开得到年,月,日
SimpleDateFormat sy=new SimpleDateFormat("yyyy");
SimpleDateFormat sm=new SimpleDateFormat("MM");
SimpleDateFormat sd=new SimpleDateFormat("dd");
String syear=sy.format(date);
String smon=sm.format(date);
String sday=sd.format(date);

java运算符

  • 算术运算符
  • 关系运算符
  • 位运算符
  • 逻辑运算符
  • 赋值运算符
  • 其他运算符
算术运算符 关系运算符 位运算符 逻辑运算符 赋值运算符 其他运算符
+、-、*、/、%、++、-- ==、!=、>、<、>=、<= &、|、^、~、<<、>>、>>> &&、||、! =、+=、-=、*=、/=、%=、<<=、>>=、&=、|=、^= ?:、instanceof

前缀自增自减法(++a,--a): 先进行自增或者自减运算,再进行表达式运算。
后缀自增自减法(a++,a--): 先进行表达式运算,再进行自增或者自减运算。

int a , b;
a = 10;
// 如果 a 等于 1 成立,则设置 b 为 20,否则为 30
b = (a == 1) ? 20 : 30;

String name = "James";
boolean result = name instanceof String; // 由于 name 是 String 类型,所以返回真

java循环

  • while循环
  • do...while循环
  • for循环
while( 布尔表达式 ) {
  //循环内容
}
do {
       //代码语句
}while(布尔表达式);
for(初始化; 布尔表达式; 更新) {
    //代码语句
}
for(声明语句 : 表达式)
{
   //代码句子
}

java分支结构

  • if语句
  • switch语句
if(布尔表达式 1){
   //如果布尔表达式 1的值为true执行代码
}else if(布尔表达式 2){
   //如果布尔表达式 2的值为true执行代码
}else if(布尔表达式 3){
   //如果布尔表达式 3的值为true执行代码
}else {
   //如果以上布尔表达式都不为true执行代码
}
switch(expression){
    case value :
       //语句
       break; //可选
    case value :
       //语句
       break; //可选
    //你可以有任意数量的case语句
    default : //可选
       //语句
}

java Number类、Math类、Character类、String类、StringBuffer类、StringBuilder 类

所有的包装类(Integer、Long、Byte、Double、Float、Short)都是抽象类 Number 的子类。Number 类属于 java.lang 包。
java中的自动装箱与拆箱:
简单一点说,装箱就是自动将基本数据类型转换为包装器类型;拆箱就是自动将包装器类型转换为基本数据类型。
xxxValue() 方法用于将 Number 对象转换为 xxx基本 数据类型的值并返回。(byteValue() ,doubleValue(),floatValue(),intValue() ,longValue(),shortValue()。以上各函数不接受任何的参数)
equals()方法判断number对象是否与参数相等。
== 它比较的是对象的地址
equals 比较的是对象的内容
valueOf()方法返回一个 Number 对象指定的内置数据类型

Integer x = 5;
x.byteValue() #拆箱,包装类转原生类
Integer.valueOf(128); #装箱,原生类转包装类
Math.cos(0) #0度的余弦值
Math.PI
Character ch = new Character('a');
String site = "www.runoob.com";
int len = site.length();
string1.concat(string2); #连接字符串
"Hello," + " runoob" + "!" #连接字符串
System.out.printf("%s,%d",变量1,变量2)
String fs = String.format("%s,%d",变量1,变量2)
StringBuffer sBuffer = new StringBuffer("菜鸟教程官网:");
sBuffer.append("www"); #append()方法 效果类似字符串的拼接

Java 的 Math 包含了用于执行基本数学运算的属性和方法,如初等指数、对数、平方根和三角函数。
Math 的方法都被定义为 static 形式,通过 Math 类可以在主函数中直接调用。
Java语言为内置数据类型char提供了包装类Character类。Character类属于 java.lang 包
String 类是不可改变的,所以你一旦创建了 String 对象,那它的值就无法改变了。
String 类的一个访问器方法是 length() 方法,它返回字符串对象包含的字符数。
length() 方法,length 属性和 size() 方法的区别:

  1. length() 方法是针对字符串来说的,要求一个字符串的长度就要用到它的length()方法;
  2. length 属性是针对 Java 中的数组来说的,要求数组的长度可以用其 length 属性;
  3. Java 中的 size() 方法是针对泛型集合说的, 如果想看这个泛型有多少个元素, 就调用此方法来查看!
    Java:String、StringBuffer 和 StringBuilder 的区别:
    String:字符串常量,字符串长度不可变。Java中String 是immutable(不可变)的。用于存放字符的数组被声明为final的,因此只能赋值一次,不可再更改。String 是被 final 修饰的,他的长度是不可变的。
    StringBuffer:字符串变量(Synchronized,即线程安全)。如果要频繁对字符串内容进行修改,出于效率考虑最好使用 StringBuffer,如果想转成 String 类型,可以调用 StringBuffer 的 toString() 方法。Java.lang.StringBuffer 线程安全的可变字符序列。在任意时间点上它都包含某种特定的字符序列,但通过某些方法调用可以改变该序列的长度和内容。可将字符串缓冲区安全地用于多个线程。
    StringBuilder:字符串变量(非线程安全)。在内部 StringBuilder 对象被当作是一个包含字符序列的变长数组。
    基本原则:
  • 如果要操作少量的数据用 String ;
  • 单线程操作大量数据用StringBuilder ;
  • 多线程操作大量数据,用StringBuffer。
    当对字符串进行修改的时候,需要使用 StringBuffer 和 StringBuilder 类。

和 String 类不同的是,StringBuffer 和 StringBuilder 类的对象能够被多次的修改,并且不产生新的未使用对象。
StringBuilder 类在 Java 5 中被提出,它和 StringBuffer 之间的最大不同在于 StringBuilder 的方法不是线程安全的(不能同步访问)。
由于 StringBuilder 相较于 StringBuffer 有速度优势,所以多数情况下建议使用 StringBuilder 类。然而在应用程序要求线程安全的情况下,则必须使用 StringBuffer 类。

#创建字符串
greeting = new String("hello");
String greeting = "hello";
char[] helloArray = { 'r', 'u', 'n', 'o', 'o', 'b'};
String helloString = new String(helloArray);  

java数组

Java 语言中提供的数组是用来存储固定大小的同类型元素。
数组可以作为参数传递给方法。
数组作为函数的返回值。

#创建数组
int[] intarray = new int[5];
int[] intarray = {1, 2, 3, 4, 5};
int[] intarray = new int[]{1, 2, 3, 4, 5};
#多维数组
String str[][] = new String[3][4];
int a[][] = new int[2][3];
a[0] = new int[2];
a[1] = new int[2];
a[0][0] = 1;
a[0][1] = 2;
a[1][0] = 3;
a[1][1] = 4;
#排序
import java.util.Arrays;
Arrays.sort(a);

java Date类、Calendar类、SimpleDateFormat类、Thread类

java.util 包提供了 Date 类来封装当前的日期和时间。

import java.util.Date;
import java.text.SimpleDateFormat;
import java.util.Thread;
import java.util.Calendar;

 // 初始化 Date 对象
Date date = new Date();
// 使用 toString() 函数显示日期时间
System.out.println(date.toString());
String sd = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(date)
Date dt = new SimpleDateFormat("yyyy-MM-dd").parse("2018-06-23") #字符串转Date类
Thread.sleep(1000*3);   // 休眠3秒
Calendar c = Calendar.getInstance();//默认是当前日期
c.setTime(dt);
c.add(Calendar.DATE, 10); #把c1对象的日期加上10,也就是c1也就表示为10天后的日期
c.add(Calendar.DATE, -10); #把c1对象的日期减去10,也就是c1也就表示为10天前的日期
Date date = c.getTime();
// 获得年份
int year = c1.get(Calendar.YEAR);
// 获得月份
int month = c1.get(Calendar.MONTH) + 1;
// 获得日期
int date = c1.get(Calendar.DATE);
// 获得小时
int hour = c1.get(Calendar.HOUR_OF_DAY);
// 获得分钟
int minute = c1.get(Calendar.MINUTE);
// 获得秒
int second = c1.get(Calendar.SECOND);

java正则表达式

java.util.regex 包主要包括以下三个类:

  • Pattern 类:
    pattern 对象是一个正则表达式的编译表示。Pattern 类没有公共构造方法。要创建一个 Pattern 对象,你必须首先调用其公共静态编译方法,它返回一个 Pattern 对象。该方法接受一个正则表达式作为它的第一个参数。
  • Matcher 类:
    Matcher 对象是对输入字符串进行解释和匹配操作的引擎。与Pattern 类一样,Matcher 也没有公共构造方法。你需要调用 Pattern 对象的 matcher 方法来获得一个 Matcher 对象。
  • PatternSyntaxException:
    PatternSyntaxException 是一个非强制异常类,它表示一个正则表达式模式中的语法错误。
import java.util.regex.Pattern;
boolean isMatch = Pattern.matches(pattern, content);#pattern是正则表达式,content是待匹配的字符串,返回true或false

Pattern p = Pattern.compile(pattern);
Matcher m = p.matcher(content);
m.find()
m.group(int) #返回匹配到的字符串
m.matches() #若pattern可以匹配整个字符串则返回true
m.lookingAt() #若pattern从一开始就能匹配就返回true
m.replaceAll(replacestring)#替换所有匹配到的内容

java方法

main 方法是被 JVM 调用的。
一个类的两个方法拥有相同的名字,但是有不同的参数列表,这叫做方法重载,重载的方法必须拥有不同的参数列表。
当一个对象被创建时候,构造方法用来初始化该对象。构造方法和它所在类的名字相同,但构造方法没有返回值。
不管你是否自定义构造方法,所有的类都有构造方法,因为Java自动提供了一个默认构造方法,它把所有成员初始化为0。
一旦你定义了自己的构造方法,默认构造方法就会失效。
Java 允许定义这样的方法,它在对象被垃圾收集器析构(回收)之前调用,这个方法叫做 finalize( ),它用来清除回收对象。

#语法
修饰符 返回值类型 方法名(参数类型 参数名){
    ...
    方法体
    ...
    return 返回值;
}
System.out.println() #这句话的用法是调用系统类 System 中的标准输出对象 out 中的方法 println()。
typeName... parameterName #可变参数语法,一个方法中只能指定一个可变参数,它必须是方法的最后一个参数。任何普通的参数必须在它之前声明。

java Stream、File、IO

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
br.readLine();#读取控制台的输入
System.out.println()
System.out.print()
System.out.write()#输出到控制台
#读取文件的两种方式
InputStream f = new FileInputStream("C:/java/hello");
File f = new File("C:/java/hello");
InputStream is = new FileInputStream(f);
is.read()
#写入数据到文件的两种方式
OutputStream f = new FileOutputStream("C:/java/hello");
File f = new File("C:/java/hello");
OutputStream os = new FileOutputStream(f);
os.write("字节数据")
File类的几种常用方法
File f = new File("C:/java/hello");
f.getName()
f.exists()
f.isDirectory()
f.isFile()
f.length() #文件的长度
f.delete()
f.listFiles()#列出该目录下所有的文件和文件夹
f.mkdirs()
f.toString()
FileWriter类#FileWriter 类从 OutputStreamWriter 类继承而来。该类按字符向流中写入数据。
FileWriter fw = new FileWriter(File file, boolean append)
FileWriter fw = new FileWriter("file_path")
fw.write("写入数据")
fw.close()
FileReader类#FileReader类从InputStreamReader类继承而来。该类按字符读取流中数据。
FileReader fr = new FileReader(File file)
FileReader fr = new FileReader("file_path", boolean append)
char[] c = new char[(int) f.length()];
fr.read(c);
for(char i: c)
  System.out.print(i);
fr.close();

总结:
以InputStream(输入)/ OutputStream(输出)为后缀的是字节流;
以Reader(输入)/ Writer(输出)为后缀的是字符流。

io流
#I/O流的典型使用方式
#读文件
public static String read(String filename) throws IOException {
        BufferedReader in = new BufferedReader(new FileReader(filename));
        String s;
        StringBuffer sb = new StringBuffer();
        while ((s = in.readLine()) != null)
            sb.append(s + "\n");
        in.close();
        return sb.toString();
    }
#写文件
public static void write(String filename) throws IOException {
        BufferedReader bf = new BufferedReader(new StringReader("abcdef\nabcdef"));
        //PrintWriter pw = new PrintWriter(new BufferedWriter(new FileWriter(filename)));
        PrintWriter pw = new PrintWriter(filename); //简写方式,仍旧是在进行缓存
        String s;
        while ((s = bf.readLine()) != null) {
            //pw.write(s + "\n");
            pw.println(s); //自动换行
        }
        pw.close();
    }
#标准输入
public static void stdIn() throws IOException {
        BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in));
        String s;
        while ((s = stdin.readLine()) != null && s.length() != 0)
            System.out.println(s);
    }
#标准输出
public static void stdOut() throws IOException {
        PrintWriter pw = new PrintWriter(System.out, true);
        pw.println("hello world");
    }

java Scanner类

// 从键盘接收数据
Scanner scan = new Scanner(System.in);
// 判断是否还有输入
if (scan.hasNextLine()) {
  String str2 = scan.nextLine();  // nextLine方式接收字符串
  System.out.println("输入的数据为:" + str2);
}
scan.close();

java异常处理

所有的异常类是从 java.lang.Exception 类继承的子类。

try{
  // 程序代码
}catch(异常类型1 异常的变量名1){
  // 程序代码
}catch(异常类型2 异常的变量名2){
  // 程序代码
}finally{
  // 程序代码
}

自定义异常:

  • 所有异常都必须是 Throwable 的子类。
  • 如果希望写一个检查性异常类,则需要继承 Exception 类。
  • 如果你想写一个运行时异常类,那么需要继承 RuntimeException 类。
image

throws 用于方法上,可抛出多个异常,每个异常的类名用逗号隔开。
throw 用在代码块中,后面跟着异常的对象,该对象可以是自定义异常,且 throw 使用在方法中。
public void test() throws Exception {
throw new Exception();
}

java继承

维护性提高,代码也更加简洁,提高代码的复用性。
继承可以使用 extends 和 implements 这两个关键字来实现继承,而且所有的类都是继承于 java.lang.Object,当一个类没有继承的两个关键字,则默认继承object(这个类在 java.lang 包中,所以不需要 import)祖先类。使用 implements 关键字可以变相的使java具有多继承的特性,使用范围为类继承接口的情况,可以同时继承多个接口(接口跟接口之间采用逗号分隔)。

继承的特性:

  • 子类拥有父类非private的属性,方法。
  • 子类可以拥有自己的属性和方法,即子类可以对父类进行扩展。
  • 子类可以用自己的方式实现父类的方法。
  • Java的继承是单继承,但是可以多重继承,单继承就是一个子类只能继承一个父类,多重继承就是,例如A类继承B类,B类继承C类,所以按照关系就是C类是B类的父类,B类是A类的父类,这是java继承区别于C++继承的一个特性。
  • 提高了类之间的耦合性(继承的缺点,耦合度高就会造成代码之间的联系)。

super 与 this 关键字:

  • super关键字:我们可以通过super关键字来实现对父类成员的访问,用来引用当前对象的父类。java 中若要在子类调用父类的方法,需使用关键字super。super 语句必须是子类构造方法的第一条语句。不能在子类中使用父类构造方法名来调用父类构造方法。 父类的构造方法不被子类继承。调用父类的构造方法的唯一途径是使用 super 关键字,如果子类中没显式调用,则编译器自动将 super(); 作为子类构造方法的第一条语句。这会形成一个构造方法链。静态方法中不能使用 super 关键字。如果子类覆盖或重写了父类的方法,则只有使用 super 才能在子类中调用父类中的被重写的方法。java文件被编译成class文件时,在子类的所有构造函数中的第一行(第一个语句)会默认自动添加 super() 语句,在执行子类的构造函数前,总是会先执行父类中的构造函数。子类的所有构造方法内部, 第一行会(隐式)自动先调用父类的无参构造函数super();如果子类构造方法第一行显式调用了父类构造方法,系统就不再调用无参的super()了。
    super 表示使用它的类的父类。super 可用于:
    调用父类的构造方法;(super();或者super(参数列表);)
    调用父类的方法(子类覆盖了父类的方法时);(super.方法名(参数列表);)
    访问父类的数据域(可以这样用但没有必要这样用)。
  • this关键字:指向自己的引用。
    this 关键字表示当前对象。可用于:
    调用当前类的构造方法,并且必须是方法的第一条语句。如:this(); 调用默认构造方法。this(参数); 调用带参构造方法。
    限定当前对象的数据域变量。一般用于方法内的局部变量与对象的数据域变量同名的情况。如 this.num = num。this.num 表示当前对象的数据域变量 num,而 num 表示方法中的局部变量。

final关键字:

final 关键字声明类可以把类定义为不能继承的,即最终类;或者用于修饰方法,该方法不能被子类重写,实例变量也可以被定义为 final,被定义为 final 的变量不能被修改。

构造器:

子类不能继承父类的构造器(构造方法或者构造函数),如果父类的构造器带有参数,则必须在子类的构造器中显式地通过 super 关键字调用父类的构造器并配以适当的参数列表。
如果父类构造器没有参数,则在子类的构造器中不需要使用 super 关键字调用父类构造器,系统会自动调用父类的无参构造器。

java重写与重载

没有override关键字,这和其他语言有区别。

方法的重写规则:

  • 参数列表必须完全与被重写方法的相同;
  • 返回类型必须完全与被重写方法的返回类型相同;
  • 访问权限不能比父类中被重写的方法的访问权限更低。例如:如果父类的一个方法被声明为public,那么在子类中重写该方法就不能声明为protected。
  • 父类的成员方法只能被它的子类重写。
    *声明为final的方法不能被重写。
  • 声明为static的方法不能被重写,但是能够被再次声明。
  • 子类和父类在同一个包中,那么子类可以重写父类所有方法,除了声明为private和final的方法。
  • 子类和父类不在同一个包中,那么子类只能够重写父类的声明为public和protected的非final方法。
  • 重写的方法能够抛出任何非强制异常,无论被重写的方法是否抛出异常。但是,重写的方法不能抛出新的强制性异常,或者比被重写方法声明的更广泛的强制性异常,反之则可以。
  • 构造方法不能被重写。
  • 如果不能继承一个方法,则不能重写这个方法。

重载规则:

  • 被重载的方法必须改变参数列表(参数个数或类型不一样);
  • 被重载的方法可以改变返回类型;
  • 被重载的方法可以改变访问修饰符;
  • 被重载的方法可以声明新的或更广的检查异常;
  • 方法能够在同一个类中或者在一个子类中被重载。
  • 无法以返回值类型作为重载函数的区分标准。

重写与重载之间的区别:

区别点 重载方法 重写方法
参数列表 必须修改 一定不能修改
返回类型 可以修改 一定不能修改
异常 可以修改 可以减少或删除,一定不能抛出新的或者更广的异常
访问 可以修改 一定不能做更严格的限制(可以降低限制)

java多态

多态是同一个行为具有多个不同表现形式或形态的能力。
多态就是同一个接口,使用不同的实例而执行不同操作。

多态的优点

  1. 消除类型之间的耦合关系
  2. 可替换性
  3. 可扩充性
  4. 接口性
  5. 灵活性
  6. 简化性

多态存在的三个必要条件

  • 继承
  • 重写
  • 父类引用指向子类对象(Parent p = new Child();)(当使用多态方式调用方法时,首先检查父类中是否有该方法,如果没有,则编译错误;如果有,再去调用子类的同名方法。)

多态的好处:可以使程序有良好的扩展,并可以对所有类的对象进行通用处理。

多态的实现方式:

  • 重写
  • 接口
  • 抽象类和抽象方法

java抽象类与抽象方法

关键字:abstract
如果一个类中没有包含足够的信息来描绘一个具体的对象,这样的类就是抽象类。
抽象类除了不能实例化对象之外,类的其它功能依然存在,成员变量、成员方法和构造方法的访问方式和普通类一样。
由于抽象类不能实例化对象,所以抽象类必须被继承,才能被使用。也是因为这个原因,通常在设计阶段决定要不要设计抽象类。

抽象类总结规定

  1. 抽象类不能被实例化(初学者很容易犯的错),如果被实例化,就会报错,编译无法通过。只有抽象类的非抽象子类可以创建对象。
  2. 抽象类中不一定包含抽象方法,但是有抽象方法的类必定是抽象类。
  3. 抽象类中的抽象方法只是声明,不包含方法体,就是不给出方法的具体实现也就是方法的具体功能。
  4. 构造方法,类方法(用static修饰的方法)不能声明为抽象方法。
  5. 抽象类的子类必须给出抽象类中的抽象方法的具体实现,除非该子类也是抽象类。

java封装

封装可以被认为是一个保护屏障,防止该类的代码和数据被外部类定义的代码随机访问。
要访问该类的代码和数据,必须通过严格的接口控制。
封装最主要的功能在于我们能修改自己的实现代码,而不用修改那些调用我们代码的程序片段。
适当的封装可以让程式码更容易理解与维护,也加强了程式码的安全性。

封装的优点

  1. 良好的封装能够减少耦合。
  2. 类内部的结构可以自由修改。
  3. 可以对成员变量进行更精确的控制。
  4. 隐藏信息,实现细节。

实现java封装的步骤:

  1. 修改属性的可见性来限制对属性的访问(一般限制为private)。
    1. 对每个值属性提供对外的公共方法(getter,setter)访问,也就是创建一对赋取值方法,用于对私有属性的访问。
class a{
private int age;
public void setAge(int newAge){
    age = newAge;
  }
public int getAge(){
    return age;
  }
}

java接口

接口(英文:Interface),在JAVA编程语言中是一个抽象类型,是抽象方法的集合,接口通常以interface来声明。一个类通过继承接口的方式,从而来继承接口的抽象方法。
接口并不是类,编写接口的方式和类很相似,但是它们属于不同的概念。类描述对象的属性和方法。接口则包含类要实现的方法。
除非实现接口的类是抽象类,否则该类要定义接口中的所有方法。
接口无法被实例化,但是可以被实现。一个实现接口的类,必须实现接口内所描述的所有方法,否则就必须声明为抽象类。另外,在 Java 中,接口类型可用来声明一个变量,他们可以成为一个空指针,或是被绑定在一个以此接口实现的对象。

接口与类的区别:

  • 接口不能用于实例化对象。
  • 接口没有构造方法。
  • 接口中所有的方法必须是抽象方法。
  • 接口不能包含成员变量,除了 static 和 final 变量。
  • 接口不是被类继承了,而是要被类实现。
  • 接口支持多继承。

接口特性:

  • 接口中每一个方法也是隐式抽象的,接口中的方法会被隐式的指定为 public abstract(只能是 public abstract,其他修饰符都会报错)。
  • 接口中可以含有变量,但是接口中的变量会被隐式的指定为 public static final 变量(并且只能是 public,用 private 修饰会报编译错误)。
  • 接口中的方法是不能在接口中实现的,只能由实现接口的类来实现接口中的方法。

抽象类和接口的区别

  • 抽象类中的方法可以有方法体,就是能实现方法的具体功能,但是接口中的方法不行。
  • 抽象类中的成员变量可以是各种类型的,而接口中的成员变量只能是 public static final 类型的。
  • 接口中不能含有静态代码块以及静态方法(用 static 修饰的方法),而抽象类是可以有静态代码块和静态方法。
  • 一个类只能继承一个抽象类,而一个类却可以实现多个接口。

java包

package pkg1[.pkg2[.pkg3…]];
import package1[.package2…].(classname|*);
包的作用

  1. 把功能相似或相关的类或接口组织在同一个包中,方便类的查找和使用。
  2. 如同文件夹一样,包也采用了树形目录的存储方式。同一个包中的类名字是不同的,不同的包中的类的名字是可以相同的,当同时调用两个不同包中相同类名的类时,应该加上包名加以区别。因此,包可以避免名字冲突。
  3. 包也限定了访问权限,拥有包访问权限的类才能访问某个包中的类。

Java 使用包(package)这种机制是为了防止命名冲突,访问控制,提供搜索和定位类(class)、接口、枚举(enumerations)和注释(annotation)等。

java数据结构

Java工具包提供了强大的数据结构。在Java中的数据结构主要包括以下几种接口和类:

  • 枚举(Enumeration)
  • 位集合(BitSet)
  • 向量(Vector)
  • 栈(Stack)
  • 字典(Dictionary)
  • 哈希表(Hashtable)
  • 属性(Properties)
import java.util.Enumeration;
import java.util.Vector;
import java.util.BitSet;
import java.util.Stack;
#Enumeration
Enumeration<String> days;
#boolean hasMoreElements( )
#测试此枚举是否包含更多的元素。
#Object nextElement( )
#如果此枚举对象至少还有一个可提供的元素,则返回此枚举的下一个元素。
while (days.hasMoreElements()){
         System.out.println(days.nextElement()); 
}

#Vector类实现了一个动态数组。
#Vector是同步访问的。
Vector类支持4种构造方法。
第一种构造方法创建一个默认的向量,默认大小为10:Vector()
第二种构造方法创建指定大小的向量:Vector(int size)
第三种构造方法创建指定大小的向量,并且增量用incr指定. 增量表示向量每次增加的元素数目: Vector(int size,int incr)
第四种构造方法创建一个包含集合c元素的向量:Vector(Collection c)

#栈是Vector的一个子类,它实现了一个标准的后进先出的栈。
boolean empty() 
测试堆栈是否为空。
Object peek( )
查看堆栈顶部的对象,但不从堆栈中移除它。
Object pop( )
移除堆栈顶部的对象,并作为此函数的值返回该对象。
Object push(Object element)
把项压入堆栈顶部。

#Dictionary 类是一个抽象类,用来存储键/值对

#Hashtable是原始的java.util的一部分, 是一个Dictionary具体的实现 。
#支持同步。
#Hashtable在哈希表中存储键/值对。

#Properties 继承于 Hashtable.表示一个持久的属性集.属性列表中每个键及其对应值都是一个字符串。
#Properties类定义了两个构造方法. 第一个构造方法没有默认值: Properties()
#第二个构造方法使用propDefault 作为默认值。两种情况下,属性列表都为空:Properties(Properties propDefault)

java集合框架

image
  1. Collection 接口
    Collection 是最基本的集合接口,一个 Collection 代表一组 Object,即 Collection 的元素, Java不提供直接继承自Collection的类,只提供继承于的子接口(如List和set)。
    Collection 接口存储一组不唯一,无序的对象。

  2. List 接口
    List接口是一个有序的 Collection,使用此接口能够精确的控制每个元素插入的位置,能够通过索引(元素在List中位置,类似于数组的下标)来访问List中的元素,第一个元素的索引为 0,而且允许有相同的元素。
    List 接口存储一组不唯一,有序(插入顺序)的对象。

  3. Set
    Set 具有与 Collection 完全一样的接口,只是行为上不同,Set 不保存重复的元素。
    Set 接口存储一组唯一,无序的对象。

  4. SortedSet
    继承于Set保存有序的集合。

  5. Map
    Map 接口存储一组键值对象,提供key(键)到value(值)的映射。

  6. Map.Entry
    描述在一个Map中的一个元素(键/值对)。是一个Map的内部类。

  7. SortedMap
    继承于 Map,使 Key 保持在升序排列。

Set和List的区别

  1. Set 接口实例存储的是无序的,不重复的数据。List 接口实例存储的是有序的,可以重复的元素。

  2. Set检索效率低下,删除和插入效率高,插入和删除不会引起元素位置改变 <实现类有HashSet,TreeSet>。

  3. List和数组类似,可以动态增长,根据实际存储的数据的长度自动增长List的长度。查找元素效率高,插入删除效率低,因为会引起其他元素位置改变 <实现类有ArrayList,LinkedList,Vector> 。

集合实现类(集合类):

  1. LinkedList
    该类实现了List接口,允许有null(空)元素。主要用于创建链表数据结构,该类没有同步方法,LinkedList 查找效率低。
  2. ArrayList
    该类也是实现了List的接口,实现了可变大小的数组,随机访问和遍历元素时,提供更好的性能。该类也是非同步的,在多线程的情况下不要使用。ArrayList 增长当前长度的50%,插入删除效率低。
  3. HashSet
    该类实现了Set接口,不允许出现重复元素,不保证集合中元素的顺序,允许包含值为null的元素,但最多只能一个。
  4. TreeSet
    该类实现了Set接口,可以实现排序等功能。
  5. HashMap
    HashMap 是一个散列表,它存储的内容是键值对(key-value)映射。
    该类实现了Map接口,根据键的HashCode值存储数据,具有很快的访问速度,最多允许一条记录的键为null,不支持线程同步。
  6. TreeMap
    继承了AbstractMap,并且使用一颗树。
List<String> list=new ArrayList<String>();
list.add("Hello");#添加元素
String[] strArray=new String[list.size()];
list.toArray(strArray);
Iterator<String> ite=list.iterator();

Map<String, String> map = new HashMap<String, String>();
map.put("1", "value1");#添加元素
map.keySet()#得到所有key
map.values()
for (Map.Entry<String, String> entry : map.entrySet()) {
       System.out.println("key= " + entry.getKey() + " and value= " + entry.getValue());
}

java泛型

下面是定义泛型方法的规则:

  • 所有泛型方法声明都有一个类型参数声明部分(由尖括号分隔),该类型参数声明部分在方法返回类型之前(在下面例子中的<E>)。
  • 每一个类型参数声明部分包含一个或多个类型参数,参数间用逗号隔开。一个泛型参数,也被称为一个类型变量,是用于指定一个泛型类型名称的标识符。
  • 类型参数能被用来声明返回值类型,并且能作为泛型方法得到的实际参数类型的占位符。
  • 泛型方法体的声明和其他方法一样。注意类型参数只能代表引用型类型,不能是原始类型(像int,double,char的等)。
public static < E > void printArray( E[] inputArray ){方法体} #泛型方法
public static <T extends Comparable<T>> T maximum(T x, T y, T z){}#上界
public class Box<T> {}#泛型类
public interface Generator<T> {T next();} #泛型接口
public static void getData(List<?> data) {}#类型通配符

<? extends T>和<? super T>的区别:

  • <? extends T>表示该通配符所代表的类型是T类型的子类。
  • <? super T>表示该通配符所代表的类型是T类型的父类。

java序列化

Java 提供了一种对象序列化的机制,该机制中,一个对象可以被表示为一个字节序列,该字节序列包括该对象的数据、有关对象的类型的信息和存储在对象中数据的类型。
将序列化对象写入文件之后,可以从文件中读取出来,并且对它进行反序列化,也就是说,对象的类型信息、对象的数据,还有对象中的数据类型可以用来在内存中新建对象。
一个类的对象要想序列化成功,必须满足两个条件:

  • 该类必须实现 java.io.Serializable 对象。(public class Employee implements java.io.Serializable)
  • 该类的所有属性必须是可序列化的。如果有一个属性不是可序列化的,则该属性必须注明是短暂的。(public transient int SSN;)

java注释

Java 支持三种注释方式。前两种分别是 // 和 /* /,第三种被称作说明注释,它以 /* 开始,以 /结束。
说明注释允许你在程序中嵌入关于程序的信息。你可以使用 javadoc 工具软件来生成信息,并输出到HTML文件中。
说明注释,使你更加方便的记录你的程序信息。
在开始的 /
* 之后,第一行或几行是关于类、变量和方法的主要描述。
之后,你可以包含一个或多个何种各样的 @ 标签。每一个 @ 标签必须在一个新行的开始或者在一行的开始紧跟星号(*).
多个相同类型的标签应该放成一组。例如,如果你有三个 @see 标签,可以将它们一个接一个的放在一起。

Java枚举类型

enum关键字

public enum Spiciness {
  NOT, MILD, MEDIUM, HOT, FLAMING
}
Spiciness howHot = Spiciness.MEDIUM;
System.out.println(howHot); //output: MEDIUM
Spiciness.values(); //output: {NOT, MILD, MEDIUM, HOT, FLAMING},返回一个数组
howHot.ordinal(); // 2, 返回对应的下标,下标从0开始。

java 并发

Java 给多线程编程提供了内置的支持。 一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。
线程状态图:



线程共包括以下 5 种状态:

  1. 新建状态(New): 线程对象被创建后,就进入了新建状态。例如,Thread thread = new Thread()。

  2. 就绪状态(Runnable): 也被称为“可执行状态”。线程对象被创建后,其它线程调用了该对象的start()方法,从而来启动该线程。例如,thread.start()。处于就绪状态的线程,随时可能被CPU调度执行。

  3. 运行状态(Running): 线程获取CPU权限进行执行。需要注意的是,线程只能从就绪状态进入到运行状态。

  4. 阻塞状态(Blocked): 阻塞状态是线程因为某种原因放弃CPU使用权,暂时停止运行。直到线程进入就绪状态,才有机会转到运行状态。阻塞的情况分三种:

(01) 等待阻塞 -- 通过调用线程的wait()方法,让线程等待某工作的完成。
(02) 同步阻塞 -- 线程在获取synchronized同步锁失败(因为锁被其它线程所占用),它会进入同步阻塞状态。
(03) 其他阻塞 -- 通过调用线程的sleep()或join()或发出了I/O请求时,线程会进入到阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入就绪状态。

  1. 死亡状态(Dead): 线程执行完了或者因异常退出了run()方法,该线程结束生命周期。

Java 提供了三种创建线程的方法:

  1. 实现Runnable接口,重写run();
  2. 继承Thread抽象类,重写run();
  3. 实现Callable接口,重写call(),并且有返回值。
class ThreadDemo extends Thread {
    ThreadDemo() {
        System.out.println("Creating " + Thread.currentThread().getName());
    }
    public void run() {
        System.out.println("Running " +  Thread.currentThread().getName() );
        try {
            for(int i = 4; i > 0; i--) {
                System.out.println("Thread: " + Thread.currentThread().getName() + ", " + i);
                // 让线程睡眠一会
                Thread.sleep(50);
            }
        }catch (InterruptedException e) {
            System.out.println("Thread " +  Thread.currentThread().getName() + " interrupted.");
        }
        System.out.println("Thread " +  Thread.currentThread().getName() + " exiting.");
    }

}
class RunnableDemo implements Runnable {
    RunnableDemo() {
        System.out.println("Creating " + Thread.currentThread().getName());
    }
    public void run() {
        System.out.println("Running " +  Thread.currentThread().getName() );
        try {
            for(int i = 4; i > 0; i--) {
                System.out.println("Thread: " + Thread.currentThread().getName() + ", " + i);
                // 让线程睡眠一会
                Thread.sleep(50);
            }
        }catch (InterruptedException e) {
            System.out.println("Thread " +  Thread.currentThread().getName() + " interrupted.");
        }
        System.out.println("Thread " +  Thread.currentThread().getName() + " exiting.");
    }

}
class CallableDemo implements Callable<String> {
    int time;
    public CallableDemo(int time ) {
        this.time = time;
    }
    public String call() throws InterruptedException {
        List<Integer> list = new ArrayList<>();
       for (int i = 1; i < time / 5; i++) {
           System.out.println(Thread.currentThread().getName() + "-" + i);
           Thread.sleep(time);
           list.add(i);
       }
       return list.toString();
    }
}
class ThreadPoolDemo implements Callable<Integer> {
    private int x;
    private int y;
    public ThreadPoolDemo(int x, int y) {
        this.x = x;
        this.y = y;
    }
    public Integer call() throws InterruptedException {
        for (int i = 1; i < 3; i++) {
            System.out.println(Thread.currentThread().getName() + "-" + i);
            Thread.sleep(50);
        }
        return x + y;
    }
}
public class ThreadTest {
    public static void main(String[] args) throws InterruptedException, ExecutionException {
        //
        for (int i = 1; i < 3; i++) {
            Thread t1 = new Thread(new ThreadDemo(), "Thread-" + i);
            System.out.println("Starting " + Thread.currentThread().getName());
            t1.start();
            //t1.join();
        }
        //
        for (int i = 1; i < 3; i++) {
            Thread t1 = new Thread(new RunnableDemo(), "Thread-" + i);
            System.out.println("Starting " + Thread.currentThread().getName());
            t1.start();
            //t1.join();
        }
        //
        for (int i = 1; i < 3; i++) {
            CallableDemo cd = new CallableDemo(50 / i);
            FutureTask<String> ft = new FutureTask<>(cd);
            Thread t = new Thread(ft, "Thread-" + i);
            t.start();
            System.out.println(ft.get()); //有问题,添加这一行,就变成串行了。

        }
        //
        ExecutorService threadPool = Executors.newFixedThreadPool(2); //创建有2个线程的线程池
        for (int i = 1; i < 6; i++) {
            ThreadPoolDemo ed = new ThreadPoolDemo(i, i);
            Future<Integer> result = threadPool.submit(ed);
            System.out.println(result.get()); //有问题,添加这一行,就变成串行了。
        }
        threadPool.shutdown(); //关闭线程池,不然程序不会终止
    }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,884评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,347评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,435评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,509评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,611评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,837评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,987评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,730评论 0 267
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,194评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,525评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,664评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,334评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,944评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,764评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,997评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,389评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,554评论 2 349

推荐阅读更多精彩内容

  • 一、Java 简介 Java是由Sun Microsystems公司于1995年5月推出的Java面向对象程序设计...
    子非鱼_t_阅读 4,160评论 1 44
  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,598评论 18 399
  • 听元宵。歌也千家,舞也千家。 吃元宵。醉也消乏,醒也消乏。 月上柳芽,黄昏影下。 诗酒喧哗,灯火万家。...
    苏文若纨素阅读 530评论 0 1