字符串是引用数据类型,不是基本数据类型。
示例代码:
public class StringConstant {
public static void main(String[] args) {
String str = "hello";
String str1 = "hello";
System.out.println(str == str1);
}
}
字符串的常量是存储在数据共享区中(jdk1.7之前是在方法区中,jdk1.8之后是在堆中),如果创建一个字符串的常量,首先会先在常量池里面去查找是否存在这个常量,如果存在就不创建直接指向,如果不存在那么就创建。
附:Java常量字符串String理解
JDK1.8关于运行时常量池, 字符串常量池的要点
内存结构:(jdk1.7之前)
内存结构:(jdk1.8之后)
字符串的常量是永远不可变的,如果对字符串拼接,实际上是新产生的字符串常量,不会在原有的字符串常量上变化。
public class StringDemo {
public static void main(String[] args) {
// "" 第一种了解即可
String s = new String();
String str = "";
System.out.println(s);
byte[] bs = {97, 98, 99};
//把字节作为ascii转换成字符连接到一起
String s1 = new String(bs);
System.out.println(s1);
byte[] bs1 = {97, 98, 99, 100, 101};
//参数1 目标数组,参数2 开始索引,参数3 截取的长度
String s2 = new String(bs1, 1, 3);
System.out.println(s2);
char [] cs = {'h','e','l','l','o'};
String s3 = new String(cs);
System.out.println(s3);
String s4 = new String(cs, 2, 2);
System.out.println(s4);
String s5 = "world";
String s6 = new String(s5);
System.out.println(s6);
}
}
面试题:String str1 = new String(“abc”);创建了几个对象?变量和类型 | 方法 | 描述 |
---|---|---|
boolean | endsWith(String suffix) | 测试此字符串是否以指定的后缀结尾。 |
boolean | equals(Object anObject) | 将此字符串与指定的对象进行比较。 |
boolean | equalsIgnoreCase(String anotherString) | 将此 String与另一个 String比较,忽略了大小写。 |
boolean | contains(CharSequence s) | 当且仅当此字符串包含指定的char值序列时,才返回true。 |
boolean | startsWith(String prefix) | 测试此字符串是否以指定的前缀开头。 |
boolean | isEmpty() | 当且仅当 length() 为 0 ,返回 true 。 |
public class Demo {
public static void main(String[] args) {
String s = "helloworld";
//判断字符串是否以某一个子字符串为结尾
boolean ends = s.endsWith("world");
System.out.println(ends);
String s1 = "HelloWorld";
//判断两个字符串的值是否相等,注意一下空指针
boolean equals = s.equals(s1);
System.out.println(equals);
//判断两个字符串的值不考虑大小写是否相等,注意一下空指针
boolean ignoreCase = s.equalsIgnoreCase(s1);
System.out.println(ignoreCase);
//判断字符串是否包含一个子字符串
boolean contains = s.contains("owo");
System.out.println(contains);
boolean starts = s.startsWith("hello");
System.out.println(starts);
//判断字符串是否是空字符, 不推荐
boolean empty = s.isEmpty();
System.out.println(empty);
//判断字符串是否是空串,推荐的用法
boolean equals1 = "".equals(s);
System.out.println(equals1);
}
}
变量和类型 | 方法 | 描述 |
---|---|---|
int | length() | 返回此字符串的长度。 |
char | charAt(int index) | 返回指定索引处的 char值。 |
int | indexOf(int ch) | 返回指定字符第一次出现的字符串中的索引。 |
int | indexOf(String str) | 返回指定子字符串第一次出现的字符串中的索引。 |
int | indexOf(String str, int fromIndex) | 从指定的索引处开始,返回指定子字符串第一次出现的字符串中的索引。 |
String | substring(int beginIndex) | 返回一个字符串,该字符串是此字符串的子字符串。 |
String | substring(int beginIndex, int endIndex) | 返回一个字符串,该字符串是此字符串的子字符串。 |
public class Demo {
public static void main(String[] args) {
String s = "OLO2343AJFLJSDF56opias32jdfadfga";
int numCount = 0;
int upperCount = 0;
int lowerCount = 0;
//遍历这个字符串
for (int i = 0; i < s.length(); i++) {
//根据索引获得对应的字符
char c = s.charAt(i);
//转换成ascii
int ascii = c;
if(ascii >= 48 && ascii <= 57){
numCount++;
}
if(ascii >= 65 && ascii <= 90){
upperCount++;
}
if(ascii >= 97 && ascii <= 122){
lowerCount++;
}
}
System.out.println("数字:"+numCount);
System.out.println("大写:"+upperCount);
System.out.println("小写:"+lowerCount);
}
}
变量和类型 | 方法 | 描述 |
---|---|---|
byte[] | getBytes() | 使用平台的默认字符集将此 String编码为字节序列,将结果存储到新的字节数组中。 |
char[] | toCharArray() | 将此字符串转换为新的字符数组。 |
static String | valueOf(boolean b) | 返回 boolean参数的字符串表示形式。 |
static String | valueOf(char c) | 返回 char参数的字符串表示形式。 |
static String | valueOf(char[] data) | 返回 char数组参数的字符串表示形式。 |
String | toUpperCase() | 使用默认语言环境的规则将此 String所有字符转换为大写。 |
String | toUpperCase(Locale locale) | 使用给定 Locale的规则将此 String所有字符转换为大写。 |
String | concat(String str) | 将指定的字符串连接到此字符串的末尾。 |
public class Demo {
public static void main(String[] args) {
Scanner s = new Scanner(System.in);
while (true){
String line = s.nextLine();
if("".equals(line)){
System.out.println("输入的字符串不合法,请重新输入");
}else{
if ("-1".equals(line)){
break;
}
// helloworld
String firstLetter = line.substring(0, 1);
//获得第一个字符后面的字符串
String rest = line.substring(1);
System.out.println("结果是:"+firstLetter.toUpperCase()+rest.toLowerCase());
}
}
System.out.println("程序结束");
}
}
变量和类型 | 方法 | 描述 |
---|---|---|
String[] | split(String regex) | 将此字符串拆分为给定 regular expression的匹配项 。 |
String | replace(char oldChar, char newChar) | 返回字符串 newChar 替换字符串 oldChar后形成的新字符串。 |
String | replace(CharSequence target, CharSequence replacement) | 将此字符串中与文字目标序列匹配的每个子字符串替换为指定的文字替换序列。 |
String | trim() | 返回一个字符串,其值为此字符串,删除了所有前导和尾随空格,其中space被定义为其代码点小于或等于 ‘U+0020’ (空格字符)的任何字符。 |
public class Demo {
/**
* 需求:找出下面字符串中li的数量
"liasdflihsdhllihsdflihsdfiligsdfglikhsdfklilisdflio"
*/
public static void main(String[] args) {
String s = "liasdflihsdhllihsdflihsdfiligsdfglikhsdfklilisdflio";
//定义一个计数器
int count = 0;
//获得li第一次出现的索引
int index = s.indexOf("li");
while (index != -1){
//计数器累加
count++;
//找下一个li
index = s.indexOf("li", index+2);
}
System.out.println("li的数量:"+count);
}
}
String str = “hello”;
str = str +”world”;
StringBuffer s = new StringBuffer("hello");
StringBuffer s1 = s.append("world");
线程是程序运行的最小的单元。
StringBuffer s = new StringBuffer(“hell”);
A线程和B线程完全同时来操作这个可变字符串
线程的安全保证了数据的安全性,但随之带来的是性能的低下。
StringBuffer s = new StringBuffer();
//获得可变字符串的容量
int capacity = s.capacity();
System.out.println(capacity);
&emsp可变字符串;默认预留了16个位置(容量)。
h | e | l | l | o | w | o | r | l | d | l | i | a | n | g | g |
---|
public class StringBufferDemo {
public static void main(String[] args) {
StringBuffer s = new StringBuffer();
int length = s.length();
System.out.println("可变字符串的长度:"+length);
//获得可变字符串的容量
int capacity = s.capacity();
System.out.println("可变字符串的容量"+capacity);
s.append("helloworld");
//获得可变字符串的容量
capacity = s.capacity();
System.out.println("可变字符串的容量"+capacity);
s.append("liangge");
//获得可变字符串的容量
capacity = s.capacity();
System.out.println("可变字符串的容量"+capacity);
StringBuffer s1 = new StringBuffer("gege");
}
}
public class StringBufferDemo {
public static void main(String[] args) {
StringBuffer s = new StringBuffer();
/*s.append("tx");
s.append(2.1f);
s.append(3.4);
s.append(new char[]{'a','b','c'});
s.append(new String("mystring"));*/
s.append("tx")
.append(2.1f)
.append(3.4)
.append(new char[]{'a','b','c'})
.append(new String("mystring"));
System.out.println(s);
}
}
public class StringBufferDemo {
public static void main(String[] args) {
StringBuffer s = new StringBuffer("helloworld");
//插入的时候一定要注意索引不要越界
s.insert(3, true);
System.out.println(s);
}
}
public class StringBufferDemo {
public static void main(String[] args) {
StringBuffer s = new StringBuffer("helloworld");
//删除指定索引处的字符串,不要越界啊
s.deleteCharAt(5);
System.out.println(s);
StringBuffer s1 = new StringBuffer("helloworld");
//删除开始索引到结束索引之间的字符串,包头不包尾,注意越界啊
s1.delete(3,5);
System.out.println(s1);
}
}
public class RandomTest {
public static void main(String[] args) {
//创建一个随机数的对象
Random r = new Random();
for (int i = 0; i < 10; i++) {
//获得一个 0~n(不包括n) 随机的整数
int nextInt = r.nextInt(1000);
System.out.println(nextInt);
}
}
}
8中基本数据类型不是类,是有局限性的。jdk5以后为每一种基本数据类型都提供了其包装类。包装类就是给基本数据类型做增强的。
基本数据类型 | byte | short | int | long | float | double | char | boolean |
---|---|---|---|---|---|---|---|---|
包装类 | Byte | Short | Integer | Long | Float | Double | Character | Boolean |
Integer的构造器:
public class Demo {
public static void main(String[] args) {
System.out.println(Integer.MAX_VALUE);
System.out.println(Integer.MIN_VALUE);
//创建一个Integer对象
Integer integer = new Integer(10);
System.out.println(integer);
//创建一个以字符串为参数的构造器, 字符串不能是非数值类型或者越界int
Integer integer1 = new Integer("100");
System.out.println(integer1);
}
}
//创建一个Integer对象
Integer integer = new Integer(10);
System.out.println(integer);
Integer integer1 = Integer.valueOf(i);
System.out.println(integer);
Integer integer = new Integer(10);
int i = integer.intValue();
System.out.println(i);
Integer integer1 = new Integer("100");
System.out.println(integer1);
Integer integer2 = Integer.valueOf("200");
System.out.println(integer2);
Integer integer = new Integer(200);
String s = integer.toString();
String s1 = integer+"";
String s2 = String.valueOf(integer);
String s = "123";
//对字符串有要求,不能越界和非数值形式
int i = Integer.parseInt(s);
System.out.println(i+1);
int j = 10;
String s1 = j+"";
String s2 = String.valueOf(j);
public class Demo {
public static void main(String[] args) {
String s = Integer.toBinaryString(100);
String s1 = Integer.toHexString(100);
String s2 = Integer.toOctalString(100);
System.out.println(s);
System.out.println(s1);
System.out.println(s2);
}
}
public class Demo {
public static void main(String[] args) {
Integer i1 = new Integer(100);
Integer i2 = new Integer(100);
//Integer是对象,不能==比较值
System.out.println(i1 == i2);
int i = 100;
int j = 100;
System.out.println(i == j);
//比较Integer的值
System.out.println(i1.equals(i2));
System.out.println(i1.intValue() == i2.intValue());
}
}
public class Person {
private String name;
/**
int的默认值是0
1.男,2.女
Integer默认值是null
1.男,2.女
*/
private Integer gender;
}
项目中建议使用Integer
public class Demo {
public static void main(String[] args) {
//自动装箱,自动把int转换成一个Integer对象
Integer i = 10;
//自动拆箱把Integer对象自动的转换成int类型
int i2 = new Integer(100);
Long l1 = 200l;
long l2 = new Long(300l);
Double d = 3.1;
double d1 = new Double(1.2);
}
}
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
自动装箱在-128~127之间是走的缓存;0 | 1 | 2 | 3 | ··· | ··· | 256 | |||
---|---|---|---|---|---|---|---|---|---|
-128 | -127 | -126 | -125 | ··· | ··· | 127 |
public class Demo {
public static void main(String[] args) {
Integer i = 1000;
Integer i1 = 1000;
Integer i2 = -126;
Integer i3 = -126;
System.out.println(i == i1);
System.out.println(i2 == i3);
}
}
public class DateDemo {
public static void main(String[] args) {
Date d = new Date();
System.out.println(d);
Date d1 = new Date(System.currentTimeMillis() - 24*60*60*1000);
System.out.println(d1);
//获得一个指定的日期的毫秒数(1970年1月1日 0点)
long time = d1.getTime();
System.out.println(time);
int year = d.getYear();
System.out.println(year+1900);
int month = d.getMonth();
System.out.println(month+1);
int day = d.getDate();
System.out.println(day);
}
@Deprecated
public static void method(){
}
}
List是有序的集合,就像我们的数组一样。我们可以把list理解为是一个长度可变的数组,而且提供了丰富的api。List集合的底层就是数组。
附:Java集合List详解
0 | 1 | 2 | 3 | 4 |
---|---|---|---|---|
劳斯莱斯 | 宾利 | 迈巴赫 | 奔驰 | 宝马 |
public static void main(String[] args) {
//创建一个list的集合
List list = new ArrayList();
//向末尾添加元素
list.add("吴用"); //0
list.add("刘唐"); //1
list.add("宋江"); //2
System.out.println(list);
//我们在1处的索引位置来插入元素,我们插入一个元素的话,该索引后面的元素都会向后移动一位
list.add(1, "晁盖");
System.out.println(list);
//创建一个集合
List list1 = new ArrayList();
list1.add("阮小五");
list1.add("阮小二");
list1.add("阮小⑦");
list.addAll(list1);
System.out.println(list);
}
ListIterator listIterator = list.listIterator();
while(listIterator.hasNext()){
//获得迭代的元素
String str = (String) listIterator.next();
if("刘唐".equals(str)){
//我们不能在一边遍历的时候一边操作集合,这样会有多线程的并发问题
//list.add("白胜");
//迭代器给我们提供了一个add方法让我们避免并发问题,但是添加的时候本次遍历不生效
listIterator.add("白胜");
}
System.out.println(str);
}
System.out.println(list);
可以使用for循环来动态的遍历List集合:
System.out.println("---------------分割线for循环遍历list-----------------------");
//int size = list.size();
//for循环对list的变量, 我们可以使用动态获得集合的长度的方式来遍历
for (int i = 0; i < list.size(); i++) {
//根据索引来获得对应的元素
String str = (String) list.get(i);
if("刘唐".equals(str)){
list.add("阮小五");
}
System.out.println(str);
}
0 | 1 | 2 | 3 | 4 |
---|---|---|---|---|
劳斯莱斯 | 宾利 | 迈巴赫 | 奔驰 | 宝马 |
List中的元素是可以重复的。
ArrayList的底层是数组的原理。
LinkedList也不是线程安全的。LinkedList是链表为原理,添加修改删除的性能高。
Vector底层也是数组的原理。线程安全的。
public static void main(String[] args) {
Vector v = new Vector();
v.add("宋江");
v.add("晁盖");
v.add("刘唐");
System.out.println(v);
Object o = v.get(1);
//Object o1 = v.elementAt(1);
System.out.println(o);
System.out.println("--------------分割线-----------------");
for (int i = 0; i < v.size(); i++) {
Object o1 = v.get(i);
System.out.println(o1);
}
System.out.println("--------------分割线-----------------");
Enumeration elements = v.elements();
while(elements.hasMoreElements()){
Object o1 = elements.nextElement();
System.out.println(o1);
}
}
泛型就是在集合中指定存储的数据类型,而且只能存储这种类型,在List<类型>必须要指定, ArrayList<>可以指定也可以不指定。基本数据类型不能作为泛型。
public static void main(String[] args) {
//定义一个集合里面指定只能存储一种数据类型
List<String> list = new ArrayList<>();
}
public static void main(String[] args) {
//定义一个集合里面指定只能存储一种数据类型
List<String> list = new ArrayList<>();
//调用集合
list.add("亮亮");
list.add("腻腻");
list.add("腻腻1");
list.add("腻腻2");
list.add("腻腻3");
//创建一个迭代器对象
Iterator<String> iterator = list.iterator();
while(iterator.hasNext()){
//获得到String类型
String next = iterator.next();
System.out.println(next);
}
}
语法:class/interface 类名/接口名
{
}
T只是泛型的一个标准,使用什么字符都可以,但是都要大写,不要使用特殊字符,建议用T。
自定义泛型类:
public class GenericTest<T> {
//定义一个泛型的属性
private T t;
public T getT() {
return t;
}
public void setT(T t) {
this.t = t;
}
}
测试:
public static void main(String[] args) {
GenericTest<String> gt = new GenericTest<>();
gt.setT("哈哈");
//获得对应的泛型的结果
String t = gt.getT();
//指定泛型是Integer类型
GenericTest<Integer> gt1 = new GenericTest<>();
gt1.setT(1);
Integer t1 = gt1.getT();
//指定泛型是Integer类型的数组
GenericTest<Integer[]> gt2 = new GenericTest<>();
gt2.setT(new Integer[]{1, 2, 4});
Integer[] t2 = gt2.getT();
//测试2个泛型
GenericTest1<String, Integer> gtt1 = new GenericTest1<>("亮哥", 30);
GenericTest1<String, Date> gtt2 = new GenericTest1<>("亮哥", new Date());
}
在jdk1.5以后出现了增强的for循环对数组、集合来做遍历。增强的for不支持并发,如果有并发的需求请使用普通的for循环。
语法:for(数据类型 变量:集合变量){
///
}
数据类型是集合或者数组中的值的类型
public static void main(String[] args) {
//定义一个数组
String [] strs = {"晁盖","宋江","刘唐","吴用"};
for(String str : strs){
System.out.println(str);
}
System.out.println("-----------------------------");
List<Integer> list = new ArrayList();
list.add(1);
list.add(2);
list.add(3);
list.add(4);
for (Integer i : list){
System.out.println(i);
}
System.out.println("-----------------------------");
//这个增强的for不能支持并发
/*for (Integer i : list){
if(i.equals(2)){
list.add(10);
}
System.out.println(i);
}*/
for (int i = 0; i < list.size(); i++) {
//根据索引获得集合的元素
Integer val = list.get(i);
//如果某个元素是2就在这个集合里加入一个10
if(val.equals(2)){
list.add(10);
}
System.out.println(val);
}
}
public static void main(String[] args) {
/**
* set是无序的
* set的元素是不可重复的,如果重复了就会自动的去掉
* set只能有一个null
*/
Set<String> set = new HashSet<>();
//给set添加元素
set.add("董卓");
set.add("张让");
set.add("何进");
set.add("李肃");
set.add(null);
System.out.println(set);
}
我们对set的唯一性深究一下(重点):
如果对象的hash值和equals都相等那么就是重复的对象。
public static void main(String[] args) {
//创建一个存储Person对象的集合
Set<Person> set = new HashSet<>();
set.add(new Person("孔明", 26));
set.add(new Person("刘备", 28));
set.add(new Person("关羽", 27));
set.add(new Person("张飞", 25));
set.add(new Person("张飞", 25));
System.out.println(set);
}
LinkedHashSet和HashSet来对比就是多了一个顺序。应用的不多。
public static void main(String[] args) {
Set<String> set = new LinkedHashSet<>();
set.add("董卓");
set.add("张让");
set.add("何进");
set.add("李肃");
set.add(null);
System.out.println(set);
}
类如果要实现比较的规则都会实现Comparable接口。
String str = "ab";
String str1 = "ab";
//字符串的比较规则是先按着第一个字符来比较,如果说一个字符串的第一个字符比另一个字符串的首字符大,那么前者就大
//如果是整数说明str大, 如果是负数str1大, 如果是0相等
int i = str.compareTo(str1);
System.out.println(i);
创建学生对象实现comparable接口:
public class Student implements Comparable<Student>{
private String name;
private int age;
public Student(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;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
@Override
public int compareTo(Student o) {
//做年龄的差
int flag = this.age - o.age;
if(flag == 0){
flag = this.name.compareTo(o.name);
}
return flag;
}
}
测试:
Student s = new Student("abc", 20);
Student s1 = new Student("abc", 20);
int i1 = s.compareTo(s1);
System.out.println(i1);
public static void main(String[] args) {
Set<Student> set = new TreeSet<>();
Student s = new Student("abc", 20);
Student s2 = new Student("abe", 20);
Student s1 = new Student("abd", 19);
set.add(s);
set.add(s1);
set.add(s2);
System.out.println(set);
}
语法:修饰符 返回值类型 方法名(数据类型…变量){
}
public class DynamicParamDemo {
public static void main(String[] args) {
//int result = add(10, 10, 20, 50, 90);
int result = add(new int[]{10, 20, 30});
System.out.println(result);
}
//数据类型 ... 变量名 这是可变参数的定义方式
//可以代表数组, 还可以代表单个数的传递
//如果调用的时候我们发现了正好能匹配的方法就不会调用可变参数的方法,如果不存在这么一个正好调用的方法就会调用可变参数的方法
public static int add(int... a){
int total = 0;
for (int i = 0; i < a.length ; i++) {
total += a[i];
}
return total;
}
/*public static int add(int a, int b){
return a + b;
}*/
}
0 | 1 | 2 | 3 | 4 |
---|---|---|---|---|
鲁智深 | 林冲 | 白胜 | 吴用 | 公孙胜 |
鲁智深 | 林冲 | 白胜 | 吴用 | 公孙胜 |
---|
花和尚 | 豹子头 | 白日鼠 | 智多星 | 入云龙 |
---|---|---|---|---|
鲁智深 | 林冲 | 白胜 | 吴用 | 公孙胜 |
我们如果想要从map中获得值,可以根据键来获得。
Map虽然是集合但是和Collection的集合体系不是同一个体系。
如果大家能理解Set那么Map的key也就能理解了。
public static void main(String[] args) {
//创建一个Map集合
Map<String, String> map = new HashMap<>();
//向集合总加元素
map.put("白日鼠","白胜");
map.put("豹子头","林冲");
map.put("小诸葛","富安");
//key只能有一个是null,值任意
/*map.put(null, null);
map.put("aaaa", null);*/
//值是可以重复的
//map.put("大诸葛","富安");
//如果存在重复的key就会把之前的覆盖掉
//map.put("小诸葛","高衙内");
System.out.println(map);
}
该映射根据其键的自然顺序进行排序,或者根据创建映射时提供的 Comparator 进行排序,具体取决于使用的构造方法;
public static void main(String[] args) {
//创建一个Map集合
Map<String, String> map = new TreeMap<>();
//向集合总加元素
map.put("b","白胜");
map.put("a","林冲");
map.put("e","富安");
map.put("c","富安");
System.out.println(map);
}
Person实现了comparable接口,我们的treemap可以根据key来做排序:
public static void main(String[] args) {
//创建一个Map集合
Map<Person, String> map = new TreeMap<>();
//向集合总加元素
map.put(new Person("白日鼠", 30),"白胜");
map.put(new Person("豹子头", 28),"林冲");
map.put(new Person("及时雨", 35),"宋江");
System.out.println(map);
}
public static void main(String[] args) {
//创建一个Map集合
Map<String, String> map = new Hashtable<>();
//向集合总加元素
map.put("b","白胜");
map.put("a","林冲");
map.put("e","富安");
map.put("c",null);
System.out.println(map);
}
public static void main(String[] args) {
//创建一个Map集合
Map<String, String> map = new LinkedHashMap<>();
//向集合总加元素
map.put("b","白胜");
map.put("a","林冲");
map.put("e","富安");
map.put("c",null);
System.out.println(map);
}
public class FileDemo {
public static void main(String[] args) {
//文件的构造器是用来创建文件对象的, 我们创建文件对象的时候要保证文件路径正确
File file = new File("D:\\tx.txt");
System.out.println(file.getName());
File file1 = new File("D:\\aaa", "拓薪教育.txt");
System.out.println(file1.getName());
//java中的File类的对象可以代表目录,也可以代表文件
File file2 = new File("D:\\aaa");
System.out.println(file2.getName());
//根据目录的文件对象创建一个文件
File file3 = new File(file2, "拓薪教育.txt");
System.out.println(file3.getName());
}
}
public class FileDemo1 {
public static void main(String[] args) throws IOException {
File file = new File("D:\\aaa\\hello.txt");
//创建一个文件
boolean newFile = file.createNewFile();
System.out.println(newFile);
}
}
public class FileDemo2 {
public static void main(String[] args) throws IOException {
//创建一个目录的对象,创建的目录上一层的路径必须正确
File file = new File("D:\\aaa\\bbb");
boolean mkdir = file.mkdir();
System.out.println(mkdir);
}
}
public class FileDemo3 {
public static void main(String[] args) throws IOException {
//创建一个目录的对象,创建的目录上一层的路径必须正确
File file = new File("D:\\aaa\\ccc\\hhh\\ggg");
boolean mkdir = file.mkdirs();
System.out.println(mkdir);
}
}
public class FileDemo4 {
public static void main(String[] args) throws IOException {
/*
File file = new File("D:\\tx.txt");
//程序删除不走回收站
file.delete();
*/
//删除路径的最后一层, 只有空目录才能被删除
File file1 = new File("D:\\aaa\\bbb");
boolean delete = file1.delete();
System.out.println(delete);
}
}
绝对路径是指目录下的绝对位置,直接到的目标位置。
相对路径就是指由这个文件所在的路径引起的跟其它文件(或文件夹)的路径关系。
public class FileDemo5 {
public static void main(String[] args) throws IOException {
File file = new File("D:\\tx.txt");
//判断文件是否存在
boolean exists = file.exists();
System.out.println(exists);
//判断这个文件对象是否是文件
boolean isFile = file.isFile();
System.out.println("判断一个文件对象是否是文件:"+isFile);
//判断这个文件对象是否是目录
boolean isDir = file.isDirectory();
System.out.println("判断一个文件对象是否是目录:"+isDir);
boolean absolute = file.isAbsolute();
System.out.println("判断一个文件对象是否是绝对路径:"+absolute);
File file1 = new File("D:\\aaa\\hello.txt");
//判断文件是否可读
boolean b = file1.canRead();
System.out.println("文件是否可读:"+b);
//判断文件是否可写
boolean w = file1.canWrite();
System.out.println("文件是否可写:"+w);
//判断文件是否是隐藏的
boolean h = file1.isHidden();
System.out.println("文件是否隐藏:"+h);
}
}
public class FileDemo6 {
public static void main(String[] args) throws IOException {
File file = new File("D:\\tx.txt");
//获得文件的绝对路径
String absolutePath = file.getAbsolutePath();
System.out.println("文件的绝对路径是:"+absolutePath);
//创建一个文件对象,用相对路径, 相对路径就是当前的项目的跟路径
File file1 = new File("a.txt");
//file1.createNewFile();
String absolutePath1 = file1.getAbsolutePath();
System.out.println("文件的绝对路径是:"+absolutePath1);
//获得的就是当前文件对象的路径
String path = file1.getPath();
System.out.println("文件的路径是:"+path);
//获得文件名
String name = file1.getName();
System.out.println("获得文件名:"+name);
//获得a.txt的大小
long length = file1.length();
System.out.println("文件的大小是:"+length);
//获得最后的修改时间
long l = file1.lastModified();
System.out.println("文件的最后修改时间:"+l);
}
}
public class FileDemo7 {
public static void main(String[] args) throws IOException {
//获得电脑磁盘的跟目录
File[] files = File.listRoots();
System.out.println(Arrays.toString(files));
//获得一个目录下的子文件对象
File file1 = new File("D:\\aaa");
//获得D:\aaa下的子文件对象
File[] files1 = file1.listFiles();
for (File f : files1){
System.out.println(f);
}
//获得子文件的名字
String[] list = file1.list();
System.out.println(Arrays.toString(list));
}
}
求一个数的阶乘:
public class FileDemo8 {
public static void main(String[] args) throws IOException {
int result = fn(5);
System.out.println(result);
}
/**
* 5! = 5*4!
* 4! = 4*3!
* 3! = 3*2!
* 2! = 2*1!
* 1! = 1
*
* fn(num) = num * fn(num - 1);
*
*/
public static int fn(int num){
int result = 1;
if(num > 1)
//方法的自身调用自身就是递归
result = num * fn(num - 1);
return result;
}
}
public class FileDemo9 {
//定义一个文件目录的层级
static int level;
public static void main(String[] args) throws IOException {
//创建一个目录
File file = new File("D:\\Program Files\\eclipse-jee-mars-1-win32-x86_64\\eclipse\\workspace\\demo1");
parseFile(file);
}
public static void parseFile(File file){
if(file == null || !file.exists()){
return;
}
//给层级来加一
level++;
//获得文件对象的子文件对象列表
File[] files = file.listFiles();
//遍历这些子文件
for(File f : files){
//打印层级的缩进
for (int i = 0; i < level; i++)
System.out.print("\t");
//打印文件
System.out.println(f.getName());
//判断这些子文件是否是目录
if(f.isDirectory()){
//递归的方式来遍历
parseFile(f);
}
}
//本层次遍历完毕把层级减回来
level--;
}
}
public class FileDemo11 {
//定义一个文件目录的层级
static int level;
public static void main(String[] args) throws IOException {
//创建一个目录
File file = new File("D:\\aaa");
parseFile(file);
}
public static void parseFile(File file){
if(file == null || !file.exists()){
return;
}
//获得文件对象的子文件对象列表
File[] files = file.listFiles();
//遍历这些子文件
for(File f : files){
//判断这些子文件是否是目录
if(f.isDirectory()){
//递归的方式来遍历
parseFile(f);
}else {
f.delete();
}
}
//删除空文件夹
file.delete();
}
}
IO概述:
IO(Input/Output):输入和输出,指的是某个设备或环境进行数据的输入或者输出。例如:键盘的输入,再比如显示器就是输出设备,输出图像。
对于java来说输入输出问题,java将它抽象成流对象来解决。
以游戏程序为中心读取文件就是输入,写入文件是输出。
流的分类:
IO流在java中从输入输出角度分类:
IO流在java中从数据的角度来分类:
文本,我们能读的懂的都可以认为是字符流。比如:文章,java文件等等
使用字符流向一个文件输入helloworld。
public class IOTest {
public static void main(String[] args) {
//创建一个文件
File file = new File("test.txt");
Writer writer = null;
try {
//IO流是需要关闭的,如果不这样设计就会不能关闭资源
writer = new FileWriter(file);
writer.write("HelloWorld");
} catch (IOException e) {
e.printStackTrace();
}finally {
//判断writer不是空防止空指针异常
if(writer != null) {
try {
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
public class IOTest4 {
public static void main(String[] args) {
Writer writer = null;
try {
//IO流是需要关闭的,如果不这样设计就会不能关闭资源
//writer = new FileWriter("test1.txt", true);
writer = new FileWriter(new File("test1.txt"), true);
writer.write("liangliang");
} catch (IOException e) {
e.printStackTrace();
}finally {
//判断writer不是空防止空指针异常
if(writer != null) {
try {
//在关闭前会做flush的事情
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
把文本写入文件中,\n代表换行,问题是不同的环境下换行的方式也不一样:
Windows: \r\n
Linux:\n
Mac:\r
public class IOTest5 {
public static void main(String[] args) {
//创建一个文件
File file = new File("test.txt");
Writer writer = null;
try {
//IO流是需要关闭的,如果不这样设计就会不能关闭资源
writer = new FileWriter(file);
for (int i = 0; i < 100; i++) {
writer.write("HelloWorld\r\n");
//每次写入10个helloworld的时候做一次flush
if(i % 10 == 0){
writer.flush();
}
}
} catch (IOException e) {
e.printStackTrace();
}finally {
//判断writer不是空防止空指针异常
if(writer != null) {
try {
//在关闭前会做flush的事情
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
public class IOTest6 {
public static void main(String[] args) {
//创建一个文件
File file = new File("test.txt");
Writer writer = null;
try {
writer = new FileWriter(file);
//定义一个数组
char[] c = {'a','b','p','b','p'};
/*writer.write(c);
//把数组中的一部分写入文件
writer.write(c, 2, 2);
writer.write(97);
*/
writer.write("helloworld", 2, 2);
} catch (IOException e) {
e.printStackTrace();
}finally {
if(writer != null) {
try {
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
public class ConverterDemo {
public static void main(String[] args) {
//创建字符流转换字节流的桥梁的对象
OutputStreamWriter ow = null;
try {
//ow = new OutputStreamWriter(new FileOutputStream("b.txt"));
//字符流通向字节流的桥梁可以指定存储的编码
ow = new OutputStreamWriter(new FileOutputStream("b.txt"),"GBK");
ow.write("中");
ow.flush();
} catch (Exception e) {
e.printStackTrace();
}finally {
try {
if(ow != null){
ow.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
Properties 类表示了一个持久的属性集。Properties 可保存在流中或从流中加载。属性列表中每个键及其对应值都是一个字符串。
public class PropTest6 {
public static void main(String[] args) {
//创建一个Properties对象
Properties prop = new Properties();
InputStream in = null;
try {
//in = new FileReader("src/names.properties");
in = PropTest6.class.getClassLoader().getResourceAsStream("names.properties");
//从字节流中来加载数据到属性对象中
prop.load(in);
System.out.println(prop);
} catch (Exception e) {
e.printStackTrace();
} finally {
if(in != null){
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
我们要序列化的对象需要实现序列化接口。
实现:
我们一般会提供一个 serialVersionUID
某个类序列化之后,如果类发生了 ,那么依然可以反序列化。
如果要是对多个对象来做序列化,一定要放在集合中。
子类要重写run方法:
public class MyThread extends Thread {
private String name;
public MyThread(String name){
this.name = name;
}
/**
* 这就是线程执行的逻辑体
*/
@Override
public void run() {
for (int i = 1; i <= 100; i++) {
System.out.println(name+"下载了"+i+"%");
}
}
}
测试代码:
public class ThreadTest {
public static void main(String[] args) {
//创建一个线程的对象
MyThread mt = new MyThread("肖申克的救赎");
//启动一个线程
mt.start();
//创建一个线程的对象
MyThread mt1 = new MyThread("当幸福来敲门");
//启动一个线程
mt1.start();
//System.out.println("方法结束");
}
}
示例代码:
public class DownLoad implements Runnable {
private String name;
public DownLoad(String name) {
this.name = name;
}
@Override
public void run() {
for (int i = 1; i <= 100; i++) {
System.out.println(name+"下载了"+i+"%");
}
}
}
测试代码:
public class ThreadTest {
public static void main(String[] args) {
//创建线程对象
Thread t = new Thread(new DownLoad("肖申克的救赎"));
Thread t1 = new Thread(new DownLoad("当幸福来敲门"));
t.start();
t1.start();
}
}
线程的并发执行通过多个线程不断的切换CPU的资源,这个速度非常快,我们感知不到,我们能感知到的就是三个线程在并发的执行。
互联网的项目中存在着大量的并发的案例,如卖火车票,电商网站。
语法:synchronized(锁对象){
//操作共享资源的代码
}
public class SaleTicketThread extends Thread {
private String name;
/**
* 定义共享的数据100张票
*/
static int tickets = 100;
//创建一个锁对象,这个对象是多个线程对象共享的数据
static Object obj = new Object();
public SaleTicketThread(String name) {
this.name = name;
}
@Override
public void run() {
//卖票是持续的
while (true){
synchronized (obj){
if(tickets > 0){
System.out.println(name+"卖出座位是"+(tickets--)+"号");
}else{
break;
}
}
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(name+"卖票结束");
}
}
测试代码:
public class ThreadTest {
public static void main(String[] args) {
SaleTicketThread t1 = new SaleTicketThread("窗口1");
SaleTicketThread t2 = new SaleTicketThread("窗口2");
SaleTicketThread t3 = new SaleTicketThread("窗口3");
SaleTicketThread t4 = new SaleTicketThread("窗口4");
t1.start();
t2.start();
t3.start();
t4.start();
}
}
public class SaleTicket implements Runnable {
/**
* 多个线程共享的100张票
*/
int tickets = 100;
//创建一个锁对象,这个对象是多个线程对象共享的数据
Object obj = new Object();
@Override
public void run() {
//卖票是持续的
while (true){
synchronized (obj){
if(tickets > 0){
System.out.println(Thread.currentThread().getName()+"卖出座位是"+(tickets--)+"号");
}else{
break;
}
}
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName()+"卖票结束");
}
}
测试代码:
public class ThreadTest {
public static void main(String[] args) {
//创建一个卖票的对象
SaleTicket st = new SaleTicket();
Thread t1 = new Thread(st, "窗口1");
Thread t2 = new Thread(st, "窗口2");
Thread t3 = new Thread(st, "窗口3");
Thread t4 = new Thread(st, "窗口4");
t1.start();
t2.start();
t3.start();
t4.start();
}
}
public class SaleTicket implements Runnable {
/**
* 多个线程共享的100张票
*/
int tickets = 100;
//创建一个锁对象,这个对象是多个线程对象共享的数据
Object obj = new Object();
@Override
public void run() {
//卖票是持续的
while (true){
if(saleTickets()){
break;
}
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName()+"卖票结束");
}
/*public boolean saleTickets(){
synchronized (obj){
boolean isFinish = false;
if(tickets > 0){
System.out.println(Thread.currentThread().getName()+"卖出座位是"+(tickets--)+"号");
}else{
isFinish = true;
}
return isFinish;
}
}*/
/**
*
* @return 如果一个对象方法上有synchronized的话那么锁的对象就是this
*/
public synchronized boolean saleTickets(){
//synchronized (obj){
boolean isFinish = false;
if(tickets > 0){
System.out.println(Thread.currentThread().getName()+"卖出座位是"+(tickets--)+"号");
}else{
isFinish = true;
}
return isFinish;
//}
}
}
public class SaleTicketThread extends Thread {
private String name;
/**
* 定义共享的数据100张票
*/
static int tickets = 100;
//创建一个锁对象,这个对象是多个线程对象共享的数据
static Object obj = new Object();
public SaleTicketThread(String name) {
super(name);
this.name = name;
}
@Override
public void run() {
//卖票是持续的
while (true){
if(saleTickets()){
break;
}
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(name+"卖票结束");
}
public static synchronized boolean saleTickets(){
boolean isFinish = false;
if(tickets > 0){
System.out.println(Thread.currentThread().getName()+"卖出座位是"+(tickets--)+"号");
}else{
isFinish = true;
}
return isFinish;
}
}
测试代码:
public class ThreadTest {
public static void main(String[] args) {
SaleTicketThread t1 = new SaleTicketThread("窗口1");
SaleTicketThread t2 = new SaleTicketThread("窗口2");
SaleTicketThread t3 = new SaleTicketThread("窗口3");
SaleTicketThread t4 = new SaleTicketThread("窗口4");
t1.start();
t2.start();
t3.start();
t4.start();
}
}
在做服务器端的程序的时候都需要给一个休眠的时间,在没有 synchronized 代码块里面会让出cpu的资源。
public static void main(String[] args) {
while(true){
System.out.println(new Date());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
休眠在同步代码块内不会让出cpu:
synchronized (ojb){
try {
//我们休眠如果在synchronized内部就不会让出cpu的资源
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
生产者生成水果,如果水果没有被买走那么就不生产处于等待状态,如果水果被消费者买走这时候消费者会通知生产者告诉他我们已经把水果买走了请生产,消费者同理,如果水果已经生产出来那么就买走,买走之后再通知生产者水果已经没了请生产。
水果篮子:
public class Basket {
private boolean isEmpty;
public boolean isEmpty() {
return isEmpty;
}
public void setEmpty(boolean empty) {
isEmpty = empty;
}
}
生产者:
public class Producer extends Thread {
private Basket basket;
public Producer(Basket basket){
super();
this.basket = basket;
}
@Override
public void run() {
while(true){
//定义一个同步代码块
synchronized (basket){
try {
if(!basket.isEmpty()){
//线程等待的状态
basket.wait();
}
System.out.println("生成水果");
basket.setEmpty(false);
//通知在这个共享对象上等待的线程
basket.notify();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
}
}
}
消费者:
package cn.tx.demo8;
public class Consumer extends Thread{
private Basket basket;
public Consumer(Basket basket){
super();
this.basket = basket;
}
@Override
public void run() {
while(true){
//定义一个同步代码块
synchronized (basket){
try {
if(basket.isEmpty()){
//线程等待的状态
basket.wait();
}
System.out.println("消费水果");
basket.setEmpty(true);
//通知在这个共享对象上等待的线程
basket.notify();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
水果篮子:
public class Basket {
private boolean isEmpty;
public boolean isEmpty() {
return isEmpty;
}
public void setEmpty(boolean empty) {
isEmpty = empty;
}
}
生产者:
package cn.tx.demo9;
public class Producer implements Runnable {
private Basket basket;
public Producer(Basket basket){
super();
this.basket = basket;
}
@Override
public void run() {
while(true){
//定义一个同步代码块
synchronized (basket){
try {
if(!basket.isEmpty()){
//线程等待的状态
basket.wait();
}
System.out.println("生成水果");
basket.setEmpty(false);
//通知在这个共享对象上等待的线程
basket.notify();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
}
}
}
消费者:
package cn.tx.demo9;
public class Consumer implements Runnable{
private Basket basket;
public Consumer(Basket basket){
super();
this.basket = basket;
}
@Override
public void run() {
while(true){
//定义一个同步代码块
synchronized (basket){
try {
if(basket.isEmpty()){
//线程等待的状态
basket.wait();
}
System.out.println("消费水果");
basket.setEmpty(true);
//通知在这个共享对象上等待的线程
basket.notify();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
测试:
public class Test {
public static void main(String[] args) {
Basket basket = new Basket();
Producer producer = new Producer(basket);
Consumer consumer = new Consumer(basket);
Thread t = new Thread(producer);
Thread t1 = new Thread(consumer);
t.start();
t1.start();
}
}
我们可以通过public final void setPriority(int newPriority)来设置线程的优先级,但是优先级并不是绝对的,只是先对来说比其他的线程得到CPU的资源机会多一些。
public class ThreadTest {
public static void main(String[] args) {
//创建一个线程的对象
MyThread mt = new MyThread("肖申克的救赎");
//创建一个线程的对象
MyThread mt1 = new MyThread("当幸福来敲门");
mt.setPriority(Thread.MAX_PRIORITY);
//启动一个线程
mt.start();
//启动一个线程
mt1.start();
//System.out.println("方法结束");
}
}
join线程会抢先拿到CPU来执行线程,然后其他的线程再来执行。
加入线程必须要在先执行的线程的start下面来执行。
public class ThreadTest {
public static void main(String[] args) {
//创建一个线程的对象
MyThread mt = new MyThread("肖申克的救赎");
//创建一个线程的对象
MyThread mt1 = new MyThread("当幸福来敲门");
MyThread mt2 = new MyThread("魔戒1");
mt.start();
try {
//加入线程必须要在先执行的线程的start下面来执行
mt.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
mt1.start();
mt2.start();
}
}
当前的线程从运行阶段回到就绪阶段,目的是把CPU的资源让给其他的线程。
public class MyThread extends Thread {
private String name;
public MyThread(String name){
this.name = name;
}
/**
* 这就是线程执行的逻辑体
*/
@Override
public void run() {
for (int i = 1; i <= 100; i++) {
System.out.println(name+"下载了"+i+"%");
//让出线程
Thread.yield();
}
}
}
守护线程会随着主线程的结束而结束。
public class ThreadTest {
public static void main(String[] args) {
//创建一个线程的对象
MyThread mt = new MyThread("肖申克的救赎");
//设置守护线程
mt.setDaemon(true);
mt.start();
System.out.println("主线程结束");
}
}
public class DeadLockThread extends Thread {
int flag;
@Override
public void run() {
if(flag == 1){
synchronized (Lock.lock1){
System.out.println("进入锁1");
synchronized (Lock.lock2){
System.out.println("进入锁1中的锁2");
}
}
}else{
synchronized (Lock.lock2){
System.out.println("进入锁2");
synchronized (Lock.lock1){
System.out.println("进入锁2中的锁1");
}
}
}
}
}
测试:
public class DeadLockTest {
public static void main(String[] args) {
DeadLockThread dt = new DeadLockThread();
dt.flag = 1;
DeadLockThread dt1 = new DeadLockThread();
dt.start();
dt1.start();
}
}