java基础学习笔记

Java版本

1996年Sun发布了Java1.0,此后采用Java1.1、J2SE1.2、J2SE1.3,采用1.X的命名方式;2006年Sun公司启用了今天的JavaSE、JavaEE、JavaME命名方式,此后的版本为JavaSE6…JavaSE12

JDK在Java1.0到Java9对应的版本号:JDK1.0、JDK1.1…JDK1.9,Java10以后JDK对应名称为JDK10、JDK11、JDK12

时间线如下:

Java SE版本 JDK版本 发布时间
Oak 1995
Java 1.0 JDK1.0 1996
Java 1.1 JDK1.1 1997
J2SE 1.2 JDK1.2 1998
J2SE 1.3 JDK1.3 2000
J2SE 1.4 JDK1.4 2002
Java SE 5.0 JDK1.5 2004
Java SE 6 JDK1.6 2006
Java SE 7 JDK1.7 2011
Java SE 8 JDK1.8 2014
Java SE 9 JDK1.9 2017
Java SE 10 JDK10 2018
Java SE 11 JDK11 2018
Java SE 12 JDK12 2019

2014年发布java 8版本,市场中约有3/4使用该版本

字与字节

bit是计算机中最小的单位;byte是计算机中基本的数据单位(计算机中最小的存储单位)

1B = 8b

例子1:

宽带,100Mbps,下载时速率为15MB/S;这两种速率b不同,因此宽带速率除以8才能得到理论下载速率

例子2:

1KB = 1024 Byte

1MB = 1024KB

JVM

JVM,Java VIrtual Machine,是运行所由Java程序的假象计算机

Java的跨平台特性:Java可以运行在任何的操作系统上,该特性是由JVM实现的:我们编写的程序运行在JVM上,JVM运行在操作系统上

Java的虚拟机本身不具备跨平台功能,每个操作系统下都有不同版本的虚拟机

JRE与JDK

JRE是Java程序的运行时环境,包含了JVM和运行时所需的核心类库

JDK是Java程序开发工具包,包含JRE和开发人员使用的工具

想要运行一个已有的Java程序,只需安装JRE即可

想要开发一个全新的Java程序,必须安装JDK

Java开发的三个步骤

编写 =》编译 =》运行(JVM运行字节码文件)

javac:编译器

java:解释器

ubuntu安装

Ubuntu18.04自带java:

ubuntu% java -version
openjdk version "11.0.4" 2019-07-16
OpenJDK Runtime Environment (build 11.0.4+11-post-Ubuntu-1ubuntu218.04.3)
OpenJDK 64-Bit Server VM (build 11.0.4+11-post-Ubuntu-1ubuntu218.04.3, mixed mode, sharing)

安装javac:

sudo apt-get install default-jdk

验证安装成功:

javac -version

切换java/javac版本:

update-alternatives --config java
update-alternatives --config javac

不过用命令行或记事本敲代码还是比较累的,可以下载IDEA编辑器方便编写Java.

jar文件生成

JAR(Java Archive)是基于ZIP文件格式的文件格式。JAR文件不仅可以被压缩发布,还可以被像编译器和JVM直接使用.

用命令行制作一个最简单的jar文件:

1.编写hello.java:

1
2
3
4
5
public class hello {
public static void main(String[] args) {
System.out.println("Hello");
}
}

2.使用javac编译成hello.class文件

3.编写manifest文件(最后一行要空出来):

Manifest-Version: 1.0
Main-Class: hello

4.将hello.classmanifest放在同一目录,命令行:

jar -cvfm hello.jar manifest hello.class

执行之后便会在当前目录生成hello.jar文件

执行它:

java -jar hello.jar

可以看到输出Hello

数据类型

数据类型 关键字 内存占用 取值范围
字节型 byte 1个字节 -128~127
短整型 short 2个字节 -32768~32767
整型 int(默认) 4个字节 -2^31~2^31次方-1
长整型 long 8个字节 -2^63~2^63-1
单精度浮点数 float 4个字节 1.4013E-45~3.4028E+38
双精度浮点数 double(默认) 8个字节 4.9E-324~1.7977E+308
字符型 char 2个字节 0-65535
布尔型 boolean 1个字节 true, false

需要注意,定义单精度浮点类型变量:

float a = 1.23f; //需要加上f或F,不然会报错

格式化输出

1
2
3
4
5
6
7
package com.test.hello;

public class Test1 {
public static void main(String[] args) {
System.out.format("小明考了%d分", 100);
}
}

数据类型的转换

自动转换

java会将取值范围小的类型自动转换为取值范围大的类型,即:

byte,short,char —> int —> long —> float —> double 

如下是一个错误的例子:

1
2
3
4
5
6
7
8
public class helloworld {
public static void main(String []args){
int a = 1;
byte b = 2;
byte c = a + b; //Error!
System.out.println(c);
}
}

byte类型占1个字节,在和int类型运算时会转换为int类型。因此此时定义的变量c不能是byte类型的,但可以是int或long等类型的

强制转换

如果想将double类型的转换为int类型,即将取值范围大的数据类型转换为取值范围小的数据类型,有个公式:

数据类型 变量名 = (数据类型)值

例如:

1
2
3
double a = 1.23;
int b = (int)a;
System.out.println(b); //1

注意:浮点转转为整数,可能会造成数据精度损失;long、int转为short,可能造成数据丢失

ascii码

char类型和int类型运算时,会将字符转为ascii码进行运算

例如定义变量:

1
2
3
4
char a = 97;
char b = 'a';
System.out.println(a); //a
System.out.println(b); //a

运算时:

1
2
3
int a = 1;
char b = 'a';
System.out.println(a+b); //98

运算符

算术运算符

加、减、乘、除、求余:

+ - * / %

自增、自减:

++ --

a++是先使用,后自增;++a是先自增,再使用:

1
2
3
4
5
int a = 1;
System.out.println(++a); //2

int b = 1;
System.out.println(b++); //1

+运算符遇到字符串时,有拼接的作用:

1
2
3
String a = "Hello";
String b = "World";
System.out.println(a+" "+b); //Hello World

赋值运算符

+= -= *= /= %=

比较运算符

> < == >= <= !=

逻辑运算符

与、或、非:

&& || !

长路与:&,不管第一个表达式是否为true,都会执行第二个表达式

短路与:&&,只有第一个表达式为true才会执行第二个表达式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package com.test.hello;

public class Test1 {
public static void main(String[] args) {
int i=1;
System.out.println(1==2 && i++==2);
System.out.println(i);//短路与,第一个表达式为false,不执行第二个表达式

int j=1;
System.out.println(1==2 & j++==2);
System.out.println(j);//长路与,执行第二个表达式
}
}
/*
false
1
false
2
*/

长路或:|:不管第一个表达式是否为true,都会执行第二个表达式

短路或:||:只有第一个表达式为false才会执行第二个表达式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package com.test.hello;

public class Test1 {
public static void main(String[] args) {
int i=1;
System.out.println(1==1 || i++==2);
System.out.println(i);//短路与,第一个表达式为true,不执行第一个表达式

int j=1;
System.out.println(1==2 | j++==2);
System.out.println(j);//长路与,第一个表达式为false,也会执行第二个表达式
}
}
/*
true
1
false
2
*/

三元运算符

格式:

变量类型 变量名 = 布尔表达式 ? 值1 : 值2

例如:

1
2
int a = 5>4?1:2;
System.out.println(a); //1

for循环

java的for循环一种用法和C语言中的用法相似,还有一种:

for (循环变量类型 循环变量名称 : 要被遍历的对象){}

访问权限

方法重载

方法重载:指在同一个类中,定义的方法名称相同,参数列表不同,与返回值类型和修饰符无关

比如,调用同一个方法,根据传入参数的数据类型输出对应类型相加运算后的结果:

1
2
3
4
5
6
7
8
9
10
11
12
public class helloworld {
public static void main(String []args){
System.out.println(add(1,2));
System.out.println(add("a","b"));
}
public static int add(int x,int y){
return x+y;
}
public static String add(String x,String y){
return x+y;
}
}

可以使用可变数量的参数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package com.test.hello;

public class Test1 {
public static void main(String[] args) {
Person h1 = new Person("鲁班七号", 20);
Person h2 = new Person("李白", 21);
Test1 t = new Test1();
t.attack(h1);
t.attack(h1, h2);
}

public void attack(Person... p){
System.out.println(p.length);
for (int i = 0; i < p.length; i++) {
System.out.println(p[i].getName()+"进行了一次攻击");
}
}
}
/*
1
鲁班七号进行了一次攻击
2
鲁班七号进行了一次攻击
李白进行了一次攻击
*/

方法重写

子类和父类存在相同的方法,但可以定义自己的行为,即与父类返回结果不同,这便是重写

例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class Animal {
public void move(){
System.out.println("animal can move");
}
}

class Dog extends Animal {
public void move(){
System.out.println("dog can move");
}
}

class Dog1{
public static void main(String[] args){
Animal a = new Animal();
Animal b = new Dog();
a.move(); //animal can move
b.move(); //dog can move
}
}

如果父类不存在子类的方法,则会抛出异常:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class Animal {
public void move(){
System.out.println("animal can move");
}
}

class Dog extends Animal {
public void stop(){
System.out.println("dog can stop");
}
}

class Dog1{
public static void main(String[] args){
Animal a = new Animal();
Animal b = new Dog();
a.move();
b.stop();
}
}

结果:

1
2
3
Error:(18, 10) java: 找不到符号
符号: 方法 stop()
位置: 类型为Animal的变量 b

参数列表必须和父类被重写的方法相同,返回值可以不同

声明为static和final的方法、构造方法不能被重写

构造方法(构造器)

该方法就好比python类中的__init__(),当创建对象时便会自动调用构造方法

构造方法必须和类同名,一个类可以有多个构造方法,构造器没有返回值,不需要void修饰

例如:

1
2
3
4
5
6
7
8
9
10
11
12
public class Test {
int x,y; //成员变量
public Test(int x,int y){
this.x = x;
this.y = y;
}
public static void main(String[] args){
Test z = new Test(1,2);
System.out.println(z.x); //1
System.out.println(z.y); //2
}
}

this

this代表当前对象

构造方法中调用构造方法:this()this(param)

调用无参构造方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package com.test.hello;

public class Test1 {
private int val;
public static void main(String[] args) {
System.out.println("main");
Test1 t1 = new Test1(1);
}

public Test1(int val) {
this();
this.val = val;
}

public Test1(){
System.out.println("Test1 obj init");
}

}
/*
main
Test1 obj init
*/

调用有参构造方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package com.test.hello;

public class Test1 {
private int val;
public static void main(String[] args) {
System.out.println("main");
Test1 t1 = new Test1(1, 2);
}

public Test1(int val) {
System.out.println(val);
}

public Test1(int val1, int val2){
this(val1);
}
}
/*
main
1
*/

static

一旦属性用了static关键字修饰,这个属性便不再属于对象,而是属于类

对于方法使用static修饰,不用实例化对象便可调用该方法(类方法/静态方法):

1
2
3
4
5
6
7
8
9
10
11
package com.test.hello;

public class Test1 {
public static void main(String[] args) {
say();
}

public static void say(){
System.out.println("hello");
}
}

带有静态修饰符的方法只能访问静态属性

静态方法在类加载时生成内存,实例方法在类实例化生成内存

类的生命周期:加载、验证、准备、解析、初始化、使用和卸载

1.准备阶段是为类的静态变量分配内存并将其初始化为默认值

public static int value=123;//在准备阶段value初始值为0 。在初始化阶段才会变为123 

2.类初始化是类加载过程的最后一步,到了初始化阶段,才真正开始执行类中定义的Java程序代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class SingleTon {
private static SingleTon singleTon = new SingleTon();
public static int count1;
public static int count2 = 0;

private SingleTon() {
count1++;
count2++;
}

public static SingleTon getInstance() {
return singleTon;
}
}

public class Test {
public static void main(String[] args) {
SingleTon singleTon = SingleTon.getInstance();
System.out.println("count1=" + singleTon.count1);
System.out.println("count2=" + singleTon.count2);
}
}

结果为:

1
2
count1=1
count2=0

先进行默认初始化(准备阶段),然后显式初始化(类初始化),开始默认初始化count1、count2都是0,p是null,然后进行显式初始化,先调用构造方法++,此时count1=1,count2=1,然后进行赋值,count1没有赋值操作,此时值仍是1,count2赋值为0,因此结果count1=1,count2=0

代码块执行顺序

执行顺序:

执行static代码块 =》执行main方法 =》 执行初始化代码块 =》 执行构造方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package com.test.hello;

public class Test1 {
private int val;
public static void main(String[] args) {
System.out.println("main");
Test1 t1 = new Test1();
}

public Test1() {
System.out.println("init");
}

static {
System.out.println("static");
}

{
System.out.println("code block");
}
}
/*
static
main
code block
init
*/

静态初始化:属于类加载的过程,只执行一次

实例初始化:每个对象创建时都会执行一次

构造方法:每个对象创建时都会执行一次

封装

意思就是使用private修饰符将某个属性隐藏起来,如要访问它,则需要调用提供的公共方法,如setXxxgetXxx

被private修饰的属性和方法,只能在本类才能被访问到

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class hello {
private String name = "test";

public void getName() {
System.out.println(name);
}

public void setName(String a) {
name = a;
}

public static void main(String argv[]) {
hello a = new hello();
a.setName("gtfly");
a.getName();
}
}

但当成员变量和形参变量名字一致时,并不能成功进行setName,例如:

1
2
3
public void setName(String name) {
name = name;
}

此时,可以使用关键字this进行优化:

1
2
3
public void setName(String name) {
this.name = name;
}

方法被哪个对象调用,方法中的this就代表那个对象

注:getXxxsetXxx方法可以通过在idea右键->Generate->Getter and Setter来自动生成(前提是已经定义好了属性)

抽象类与接口

抽象类

抽象类不能被实例化,不能用于static或构造方法中;抽象方法不能有方法体,其子类必须重写抽象方法且有方法体

Test1.java:

1
2
3
4
5
6
package com.test.hello;

public abstract class Test1 {
public abstract void say();
//如果声明为public void say(){},则子类不需要重写该方法
}

Person.java:

1
2
3
4
5
6
7
8
9
10
11
package com.test.hello;

public class Person extends Test1{
public static void main(String[] args) {
Person person = new Person();
person.say();
}
public void say(){
System.out.println("Hello");
}
}

接口

接口主要作用就是封装方法,定义类似于类但不是类,它不能创建对象,但可以被实现;一个实现接口的类,可以看做接口的子类

定义:

1
2
3
4
5
6
public interface 接口名{
public abstract void method(); //抽象方法,供子类实现使用
public default void method(){} //默认方法,供子类调用或重写
public static void method(){} //静态方法,供接口直接调用
private void method(){} //私有方法,供接口中的默认方法或静态方法调用
}

接口的实现:

1
2
3
4
class 类名 implements 接口名{
//重写接口中的抽象方法,必须
//重写接口中的默认方法,可选
}

例子:

新建接口文件say.java

1
2
3
4
5
package com.java.test;

public interface say {
public abstract void sayHello();
}

新建接口实现文件hello.java

1
2
3
4
5
6
7
8
9
10
11
12
13
package com.java.test;

public class hello implements say{
@Override
public void sayHello(){
System.out.println("hello");
}

public static void main(String[] args){
hello a = new hello();
a.sayHello();
}
}

并且一个类可以实现多个接口

抽象类与接口区别

子类可以继承一个抽象类,可以实现多个接口

匿名类

匿名类可以在一个类中创建一个类,并且不需要类名称;匿名类通常继承一个类或实现一个接口

Person.java:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package com.test.hello;

public class Person{
public void CreateClass(){
Test1 t1 = new Test1(){
public void say(){
super.say();
System.out.println("Person");
}
};
t1.say();
}

public static void main(String[] args) {
Person person = new Person();
person.CreateClass();
}
}

Test1.java:

1
2
3
4
5
6
7
package com.test.hello;

public class Test1 {
public void say(){
System.out.println("Test1");
};
}

多态

多态是指同一行为,具有多种表现形式

前提:1.继承或实现 2.方法重写 3.父类引用指向子类对象

格式:

1
2
父类类型 变量名 = new 子类;
变量名.方法名

使用多态方式调用方法时,首先检查父类中是否有该方法,如果有,则执行的是子类重写的方法,如果没有,则编译错误

例子:

父类Animal.java:

1
2
3
4
5
package com.java.test;

public abstract class Animal {
public abstract void eat();
}

子类Dog.java:

1
2
3
4
5
6
7
package com.java.test;

public class Dog extends Animal{
public void eat() {
System.out.println("dog eat");
}
}

子类Cat.java:

1
2
3
4
5
6
7
package com.java.test;

public class Cat extends Animal {
public void eat() {
System.out.println("cat eat");
}
}

测试类test.java:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package com.java.test;

public class test {
public static void main(String[] args){
Cat a = new Cat();
Dog b = new Dog();

test t = new test();
t.showAnimalEat(a);
t.showAnimalEat(b);
}

public void showAnimalEat(Animal s){
s.eat();
}
}

showAnimalEat()方法用父类类型接收子类对象,在执行eat()时是执行的子类重写的方法,因此可以大大提升扩展性,无论以后再多子类出现,也不必去额外定义Eat方法

Object类

java中所有类都直接或间接继承自java.lang.Object类

getClass()会返回对象执行时的Class实例,此实例调用getName()方法可以取得类名称;

toString()可以将一个对象返回为字符串形式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package com.test.hello;

public class Test1 {
public static void main(String[] args) {
Test1 t1 = new Test1();
System.out.println(t1.getClass());//获取Class实例
System.out.println(t1.getClass().getName());//获取类名称

System.out.println(t1);

}

public String toString() {//重写Object对象的toString方法
return "啊哈哈哈哈";
}
}
/*
class com.test.hello.Test1
com.test.hello.Test1
啊哈哈哈哈
*/

泛型

泛型提供了编译时类型安全监测机制

泛型的本质是参数化类型,也就是所操作的数据类型被指定为一个参数。

常用内置类

Scanner类

实现从键盘输入数据到程序中

1
2
3
4
5
6
7
8
9
10
11
12
13
import java.util.Scanner;

public class Test {
public static void main(String[] args){
Scanner s = new Scanner(System.in);
String test = s.next();
Test t = new Test();
t.say(test);
}
public void say(String a){
System.out.println(a);
}
}

Random类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import java.util.Random;

public class Test {
public static void main(String[] args){
Test t1 = new Test();
Random random = new Random();
int num = random.nextInt(); //获取int范围,正负都有
int num = random.nextInt(5); //表示范围[0,5)
t1.say(num);
}
public void say(int a){
System.out.println(a);
}
}

List

对象数组

Person.java:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package com.test.hello;

public class Person {
private String name;
private int age;

public Person(String name, int age) {
this.name = name;
this.age = age;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public int getAge() {
return age;
}

public void setAge(int age) {
this.age = age;
}
}

Test1.java:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
package com.test.hello;
import com.test.hello.Person;
public class Test1 {
public static void main(String[] args) {
Person[] arr = new Person[3];

Person one = new Person("gtfly", 20);
Person two = new Person("gtfly1", 30);
Person three = new Person("gtfly2", 40);

arr[1] = two;
System.out.println(arr[1].getName()); //gtfly1
}
}

数组有一个缺点,程序一旦运行,长度不可以发生改变

ArrayList类

ArrayList是大小可变的数组的实现;

对于ArrayList来说,有一个尖括号<E>代表泛型;泛型:装在集合中的元素,全部都是统一的类型

直接打印ArrayList集合,得到的是内容而不是地址值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
package com.test.hello;

import java.util.ArrayList;

public class Test1 {
public static void main(String[] args) {
//1.7+ 右边尖括号中的类型可以省略
ArrayList<String> list = new ArrayList<>();
//添加元素
list.add("gtfly1");
list.add("gtfly2");
list.add("gtfly3");
list.add("gtfly4");
list.add("gtfly5");
list.add("gtfly6");
list.add("gtfly7");
list.add("gtfly8");
list.add("gtfly9");
list.add("gtfly10");
list.add("gtfly11");
//获取第11个元素
System.out.println(list.get(10));
//删除第11个元素
list.remove(10);
System.out.println(list);
//获取集合长度
System.out.println(list.size());
//清空所有元素
list.clear();
System.out.println(list);
/*
gtfly11
[gtfly1, gtfly2, gtfly3, gtfly4, gtfly5, gtfly6, gtfly7, gtfly8, gtfly9, gtfly10]
10
[]
*/
}
}

ArrayList中尖括号中的类型必须是引用类型,如果想使用基本类型,必须使用基本类型对应的包装类:

1
2
3
4
5
6
7
int		Integer
byte Byte
float Float
short Short
char Character
double Double
boolean Boolean

Vector类

Vector是矢量队列,和ArrayList不同,Vector中的操作是线程安全的(同步访问)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import java.util.Enumeration;
import java.util.Vector;

public class Test {
public static void main(String[] args) {
Vector v = new Vector();//创建一个默认的向量,默认大小为10
v.addElement(new Integer(123));//将指定的组件添加到此向量的末尾
v.addElement(new String("hello"));
System.out.println(v.capacity());//返回此向量的当前容量
System.out.println(v.size());//返回此向量中的组件数
Enumeration e = v.elements();//返回Enumeration对象
while(e.hasMoreElements()){//测试此枚举是否包含更多元素
System.out.println(e.nextElement());//如果此枚举对象至少还有一个可供提供的元素,则返回此枚举的下一个元素
}
}
}

String类

创建字符串3种构造方法+1种直接创建:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package com.test.hello;

public class Test1 {
public static void main(String[] args) {
//创建空字符串
String s1 = new String();
System.out.println(s1);
//利用char
char[] c = {'A', 'B', 'C'};
String s2 = new String(c);
System.out.println(s2);
//利用byte
byte[] b = {97, 98, 99};
String s3 = new String(b);
System.out.println(s3);
//直接创建
String s4 = "hello";
System.out.println(s4);
}
}

对于字符串,只要有双引号,没有使用new,也是字符串对象

字符串比较

使用==是进行地址值的比较,字符串内容比较可以使用equal方法:

1
2
3
4
5
6
7
8
9
10
11
package com.test.hello;

public class Test1 {
public static void main(String[] args) {
byte[] b = {97, 98, 99};
String s3 = new String(b);

String s4 = "abc";
System.out.println(s3.equals(s4)); //true
}
}

字符串截取

substring方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
package com.test.hello;

public class Test1 {
public static void main(String[] args) {
String s4 = "abcd";
System.out.println(s4.substring(1)); //截取index直到末尾的字符串
System.out.println(s4.substring(1,2)); //截取[begin, end)中间的字符串
}
}
/*
bcd
b
*/

字符串格式转换

1
2
3
toCharArray 转换为字符数组
getBytes 转换为字节数组
replace 替换字符

example:

1
2
3
4
5
6
7
8
9
10
package com.test.hello;

public class Test1 {
public static void main(String[] args) {
String s4 = "abcd";
System.out.println(s4.toCharArray()[0]);//a
System.out.println(s4.getBytes()[0]);//97
System.out.println(s4.replace('a', 'e'));//ebcd
}
}

字符串分隔

split方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package com.test.hello;

public class Test1 {
public static void main(String[] args) {
String s4 = "a,b,c,d";
String[] arr = s4.split(",");
//快捷键:arr.fori
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
}
}
/*
a
b
c
d
*/

File类

使用File类创建一个File对象:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package com.test.hello;

import java.io.File;

public class Test1 {
public static void main(String[] args) {
File f1 = new File("/etc/"); //根据pathname创建File实例
System.out.println(f1);

File f2 = new File(f1, "passwd"); //根据parent抽象路径名和子路径创建File实例
System.out.println(f2);

File f3 = new File("/etc/", "passwd"); //根据父路径和子路径创建File实例
System.out.println(f3);
}
}
/*
/etc
/etc/passwd
/etc/passwd
*/

常见方法

获取文件或目录的信息:

1
2
3
4
5
6
7
8
9
10
String getName():     抽象路径名表示的文件或目录的名称。
long length() : 抽象路径名表示的文件的长度。(只能返回文件大小,不能直接返回目录大小)
boolean exists() : 抽象路径名表示的文件或目录是否存在。
boolean isHidden() : 抽象路径名指定的文件是否是一个隐藏文件。
boolean canRead() : 应用程序是否可以读取此抽象路径名表示的文件。
boolean canWrite() : 应用程序是否可以修改此抽象路径名表示的文件
long lastModified() : 抽象路径名表示的文件最后一次被修改的时间。(毫秒值)
String toString() : 抽象路径名的路径名字符串。boolean isAbsolute(): 测试File对象对应的文件或目录是否是绝对路径。
String getParent() : 抽象路径名父目录的路径名字符串;如果此路径名没有指定父目录,则返回 null。(返回父目录名称)
File getParentFile() :抽象路径名父目录的抽象路径名;如果此路径名没有指定父目录,则返回 null。(返回父目录的File对象)

获取文件或目录的路径:

1
2
3
4
5
String getPath() : 将此抽象路径名转换为一个路径名字符串。
File getAbsoluteFile() : 返回此抽象路径名的绝对路径名形式。
String getAbsolutePath():返回此抽象路径名的绝对路径名字符串。 返回绝对路径,从根目录开始导航
File getCanonicalFile(): 返回此抽象路径名的规范形式。
String getCanonicalPath() :返回此抽象路径名的规范路径名字符串。规范路径就是路径里没有./或../或/,会把这些自动解析

文件或目录的增、删、改、比较:

1
2
3
4
5
6
boolean createNewFile():当且仅当不存在具有此抽象路径名指定名称的文件时,不可分地创建一个新的空文件。(只创建文件)
boolean delete(): 删除此抽象路径名表示的文件或目录。(可以删除文件或删除空目录)删除成功,返回true,失败false。
boolean equals(Object obj):测试此抽象路径名与给定对象是否相等。
boolean mkdir() : 创建此抽象路径名指定的目录。(只能创建一级目录)必须确保父目录存在,否则创建失败。
boolean mkdirs(): 创建此抽象路径名指定的目录,包括所有必需但不存在的父目录。 (可以创建多级目录)如果父目录不存在,会一同创建父目录
boolean renameTo(File dest) :重新命名此抽象路径名表示的文件。(可以给文件或目录重命名)

判断文件、目录:

1
2
boolean isFile() :测试此抽象路径名表示的文件是否是一个标准文件。
boolean isDirectory():测试此抽象路径名表示的文件是否是一个目录。

获取目录:

1
2
3
String[] list() :返回一个字符串数组,这些字符串指定此抽象路径名表示的目录中的文件和目录。
File[] listFiles() :返回一个抽象路径名数组,这些路径名表示此抽象路径名表示的目录中的文件。(获取下一级的文件/目录的File对象)
static File[] listRoots():列出可用的文件系统根。

输入输出流

FileInputStream、FileOutputStream
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
package com.test.hello;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;

public class Test1 {
public static void main(String[] args) {
File f1 = new File("/Users/gtfly/Desktop/1.txt");

try{
FileOutputStream fos = new FileOutputStream(f1);//输出流,写文件
byte b[] = "啊哈哈哈哈哈哈".getBytes();
fos.write(b);
fos.close();
}catch(Exception e){
e.printStackTrace();
}

try{
FileInputStream fis = new FileInputStream(f1);//输出流,读文件
byte[] buf = new byte[1024];
int len = fis.read(buf);
System.out.println(new String(buf, 0, len));
fis.close();
}catch(Exception e){
e.printStackTrace();
}
}
}
FileReader、FileWriter

避免因字节流出现的乱码现象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package com.test.hello;

import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;

public class Test1 {
public static void main(String[] args) {
File f1 = new File("/Users/gtfly/Desktop/1.txt"); //写入文件
try{
FileWriter fw = new FileWriter(f1);
fw.write("卧槽有蚊子");
fw.close();
}catch(Exception e){
e.printStackTrace();
}

try{
FileReader fr = new FileReader(f1); //读取文件
char buf[] = new char[1024];
int len = fr.read(buf);
System.out.println(new String(buf));
}catch(Exception e){
e.printStackTrace();
}
}
}

带缓存的输入输出流

BufferedReader类与BufferedWriter类分别继承Reader与Writer类,具有内部缓存机制

缓存流会先将数据写入缓冲区,会在达到缓冲区一定量时才会进行IO操作,这样可以减少IO操作;如果想要立刻将缓存区的数据写入输出流,需要调用flush()方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
package com.test.hello;

import java.io.*;

public class Test1 {
public static void main(String[] args) {
File f1 = new File("/Users/gtfly/Desktop/1.txt");
String[] s = {"卧槽", "有蚊子"};
try{
FileWriter fw = new FileWriter(f1);
BufferedWriter bw = new BufferedWriter(fw);
for (int i = 0; i < s.length; i++) {
bw.write(s[i]);
bw.newLine();//换行
}
bw.close();
fw.close();
}catch (Exception e) {
e.printStackTrace();
}

try{
FileReader fr = new FileReader(f1);
BufferedReader br = new BufferedReader(fr);
String str = null;
int i=0;
while((str = br.readLine()) != null){
i++;
System.out.format("第%d行:%s\n", i, str);
}
br.close();
fr.close();
}catch(Exception e){
e.printStackTrace();
}
}
}
/*
第1行:卧槽
第2行:有蚊子
*/

设计模式

单例模式

一个类有且仅有一个实例,并且自行实例化向整个系统提供

数据库连接使用单例模式:

1
2
3
4
5
6
7
8
public class TrainDB {
private static TrainDB instance = new TrainDB();
public static TrainDB getInstance() {
return instance;
}
private TrainDB() { // 建立连接的代码...
}
}

1.构造方法私有化

2.提供全局访问的方法

3.静态属性指向实例