JAVA重学之02
文章目录
注意:除了八大基本类型外,都是引用类型。
数据类型转换
自动转换
强制转换
1.(目标数据类型)数据 如Int a=1; byte b=(byte) a;
2.用String.valueof(数据),将数据转化为字符串形式。
数组
定义:
1.一种容器,可以存储多个同一类型的数据值,它是一种引用数据类型,运行时数组长度不能改变。
2.索引开始从0到length-1;
初始化:
动态初始化(指定长度):数据类型[] 数组名称=new 数据类型[数组长度];
使用动态化初始数组时,其中的元素会自动拥有一个默认值:
如果整数型:默认0
如果浮点型:默认0.0
如果字符类型:默认’\u0000’
如果布尔类型:默认false
如果引用类型:默认null
静态初始化(指定内容): 数据类型[] 数组名称=new 数据类型[]{数组元素1,数组元素2…n};可以简写形式:数据类型[]数组名称= {数组元素1,数组元素2…n};
动态初始化也有赋默认值的过程,只不过马上就替换成了大括号当中的具体数值。
动态初始化可以拆分为两个步骤,静态的不能拆分:
如 int [] arry=new int[5];
拆分为:int[]arry; arry=new int[5];
使用建议:
知道具体内容时用静态初始化,不知道具体内容用动态初始化。
java的内存需要划分成为5个部分:
前三个区在数组中的应用:
单个数组初始化形成,赋值的过程
注意数组名:代表的是首元素的地址
两个引用指向同一数组的内部运行过程
常见的问题
数组越界
每个数组的索引都有一个范围,即[0,length-1],在访问数组的元素超出这个范围就会报错。
ArrayIndexOutOfBoundsException ,数组越界异常。
例子:
ackage demo02;
public class test1 {
public static void main(String[] args) {
int [] arrayA=new int[3];
arrayA[0]=1;
arrayA[1]=2;
arrayA[2]=3;
System.out.println(arrayA[1]);
System.out.println(arrayA[3]);//不能超过定义时的数组角标
}
}
2
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 3
at demo02.test1.main(test1.java:11)
Process finished with exit code 1
空指针异常
数组必须进行初始化(即new,不new 只能叫定义)才可以使用其中的元素。如果只是赋了一个null值(数组是引用型,所有引用型都能赋值为一个null,代表其中什么都没有,此时没有初始化不能赋其他值),没有进行new创建,那么将发生空指针异常NullPointerException。
问题原因:忘记初始化(即没有new )
解决:补上new.
例子:
package demo02;
public class test2 {
public static void main(String[] args) {
int []arrayA;//动态初始化数组,分两步,先定义在初始化。这步为定义
//arrayA= new int[3];//这步为初始化,有new 为初始化,就算静态初始化的省略格式,也是有的。
// arrayA=3;//现在赋其他值会报错
arrayA=null;//只能赋null
System.out.println(arrayA[0]);
}
}
Exception in thread "main" java.lang.NullPointerException
at demo02.test2.main(test2.java:9)
Process finished with exit code 1
补上new后
package demo02;
public class test2 {
public static void main(String[] args) {
int []arrayA;//动态初始化数组,分两步,先定义在初始化。这步为定义
arrayA= new int[3];//这步为初始化,有new 为初始化,就算静态初始化的省略格式,也是有的。
// arrayA=3;//现在赋其他值会报错
arrayA=null;//只能赋null
System.out.println(arrayA);
}
}
null
Process finished with exit code 0
获取数组的长度
数组名称.length;
package demo02;
public class test3 {
public static void main(String[] args) {
// int [] arrayA=new int[3];//动态初始化一眼能看到数组长度
// int []arrayA={1,2,2};//静态初始化的,数据少时能一眼看出
int []arrayA={1,2,2,33,4,4,5,5,55,3,2,324,341,4,23};//数据多时不能一眼看出
int len=arrayA.length;//可以用这个直接获取
System.out.println("数组长度为:"+len);
}
}
数组长度为:15
数组长度在,程序运行期间不能够改变。
初始化new的东西放在了堆中,一开始初始化时,内存空间是分配好的。
数组的遍历
package demo02;
public class test4 {//数组遍历
public static void main(String[] args) {
int[] arrayA={22,3,44,44};
//原始方式
System.out.println(arrayA[0]);
System.out.println(arrayA[1]);
System.out.println(arrayA[2]);
System.out.println(arrayA[3]);
System.out.println("==========");
//for循环
//4.fori
for (int i = 0; i < 4; i++) {
System.out.println(arrayA[i]);//当改动数组时只用改动一个值,4.
}
System.out.println("============");
// for循环+数组长度
//arrayA.fori自动生成
for (int i = 0; i < arrayA.length; i++) {
System.out.println(arrayA[i]);//不用改动数组值
}
System.out.println("============");
//foreach()方法
for (int i:arrayA//foreach()方法,注意它不能改变值,只能访问
) {
System.out.println(i);//这里直接是i,不是arrayA[i],因为这里的i代表的是数组元素,不是索引
}
//for循环加数组长度
}
}
求最大值遍历方法:
package demo02;
public class test4 {//数组遍历
public static void main(String[] args) {
int[] arrayA={22,3,44,44};
//求最大值
//方一。foreach
int max=arrayA[0];
for (int i:arrayA
) {
if (i>max)
{
max=i;
}
}
System.out.println(max);
System.out.println("======");
// 方二
for (int i = 0; i < arrayA.length; i++) {
if (arrayA[i]>max)
{
max=arrayA[i];
}
}
System.out.println(max);
}
}
44
======
44
数组的翻转
例子:
我的代码:
package array.example;
public class arrayReverse {
public static void main(String[] args) {
//先用数组储存数据
int []array=new int[]{10,20,30,40,50};
//打印
for (int i = 0; i < array.length; i++) {
System.out.println(array[i]);
}
System.out.printf("===========");
//翻转,用循环
/*初始化:int max=array.length,min=0
* 判断条件:min<max
* 步进表达式:max--,min++
* 循环体:*/
for (int max=array.length-1,min=0;min<max; min++,max--) {
int temp=array[max];
array[max]=array[min];
array[min]=temp;
}
//再次打印
for (int i = 0; i < array.length; i++) {
System.out.println(array[i]);
}
}
}
数组当方法参数
数组也能当返回值
我的代码验证
IO
Reader结尾的为字符输入输出流,Stream结尾的为字节输入输出流
概述:数据的流动,以内存为基准。分为
输入流(input):把数据从其他设备读取到内存。
输出流(output):把数据从内存写出到其他设备。
流向内存为输入流,流出内存为输出流,在java.io包下,输入也叫读取数据,输出也叫写出数据。
字节
任意文件以字节储存,可以用字节的输入输出流来处理图片文件等的非中文文件
抽象类都不能创建对象的,需要它的实现类才行。
字节输出流(写出)
单个字节的输出:
void.write(int b);
package file.FileOutstreamdemo;
import java.io.FileOutputStream;
import java.io.IOException;
/**
* @author 不悔
* @description demo01--文件输出流
* @date 2021/1/25 12:30
*/
public class demo01 {
public static void main(String[] args) throws IOException {
FileOutputStream fos=new FileOutputStream("D:\\桌面\\java相关APP\\a.text");//括号里可以是绝对路径(更好,避免错误),也可以是相对路径,会查看该路径有没有指定文件,没有的话,会建一个
fos.write(97);
//释放资源
fos.close();//流会占据一定内存,使用完毕要关闭,会提高程序的效率
}
}
其中IOException 是其他所有IO异常的父类,使用它,就不用定义其他异常了
写入数据的原理(java程序–》JVM(java虚拟机)————》os(操作系统)————》os调用本身写数据的方法——》把数据写入文件中)
文件找不到异常是IO异常的子类
数据写入时字节,打开任意文本编辑器时,它会自动把字节转化为字符。(单个数字(如1。 12属于2个字节)或英文占1个字节,单个中文占1个字符,1个字符=2个字节=16 bit)转字符是如果是数字查ASCII表,如果是其他值,查询系统默认码表,中文系统是GBK
十进制转二进制:可用计算器查看————》程序员
多个字节的输出:
void write(byte[] b) or
void write(byte[] b, int off, int len)
写 len字节从指定的 byte数组起始偏移 off到输出流。off 是起始位置,len是长度
package file.FileOutstreamdemo;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.reflect.Array;
import java.util.Arrays;
/**
* @author 不悔
* @description Demo02--多个字节的输出
* @date 2021/1/25 13:16
*/
/*void close()
关闭此输出流并释放与流关联的任何系统资源。
void flush()
刷新输出流,使缓存数据被写入到流。
//写单个字节输出流
void write(int b)
将指定的 byte到输出流。*/
//写多个字节的输出流的方法,利用数组
/* void write(byte[] b)
写 b.length字节输出流。
void write(byte[] b, int off, int len)
写 len字节从指定的 byte数组起始偏移 off到输出流。*/
public class Demo02 {
public static void main(String[] args) throws IOException {
//创建 FileOutputStream对象,构造方法中绑定要写入的文件路径
FileOutputStream fos = new FileOutputStream(new File("D:\\桌面\\java相关APP\\b.text"));//以文件的形式创建
//在文件中显示一百,需要3个字节
/* fos.write(49);//49ASCII值为1
fos.write(48);//48ASCII值为0
fos.write(48);//48ASCII值为0
fos.close();*/
//上面的一个一个字节打,太没效率,用数组方法
/* void write(byte[] b)
写 b.length字节输出流。
以上方法一次可写多个字节:
如果写的第一个字节是整数(0-127),那么显示的时候会查询ASCII值
如果写的第一个字节是负数,它会和第二字节组成一个中文 提示(查询系统默认码表(GBK)),如果第3个也是负数则会和第4个组成。。*/
byte [] bytes={65,66,67,68};//ABCD
/*byte [] bytes1={-65,66,-67,68,69};//緽紻E,这不是乱码,是中文提示
fos.write(bytes);
fos.write(bytes1);
fos.close();*/
/*
void write(byte[] b, int off, int len)
写 len字节从指定的 byte数组起始偏移 off到输出流。off 是起始位置,len是长度*/
/*fos.write(bytes,1,2);
fos.close();*/
//写入字符串的方法:可以使用String类中的方法把字符串,转换为字节数组,byte[]getBytes()把字符串转换为字符数组。
byte[] bytes2="你好".getBytes();
System.out.println(Arrays.toString(bytes2));//验证,以负数的形式存在[-28, -67, -96, -27, -91, -67]
fos.write(bytes2);
fos.close();
}
}
注意这个方法:" ".getbytes();讲字符串转换为字节数组
末尾续写和换行
package file.FileOutstreamdemo;
import java.io.FileOutputStream;
import java.io.IOException;
/**
* @author 不悔
* @description Demo03---文件输出流的续写和换行
* @date 2021/1/25 16:54
*/
public class Demo03 {
/*
public FileOutputStream(String name,
boolean append)
throws FileNotFoundException
创建一个文件输出流,用指定的路径写入文件。如果append= true,然后字节将被写入到文件的末尾而不是开头,不会覆盖原内容(实现续写,不改变程序,再运行一遍也会直接在后面续写)。
*/
public static void main(String[] args) throws IOException {
FileOutputStream fos=new FileOutputStream("month1.day.02\\b.text",true);//在本文件夹下的,可以在左侧目录看到
fos.write("你好".getBytes());
fos.write("你好".getBytes());
/*windows 换行为\r\n
* linux:/n
* mac: /r*/
fos.write("\r\n".getBytes());//想要换行,直接加一个这个语句
fos.write("你好".getBytes());
fos.write("你好".getBytes());
fos.write("你好".getBytes());
fos.close();
}
}
windows 换行为\r\n
* linux换行为:/n
* mac换行为: /r
字节输入流(读取)
单个字符读取:
注意:输入流的read()方法是有返回值的,返回值为int
package file.FileInputStreamDemo;
import java.io.FileInputStream;
import java.io.IOException;
/**
* @author 不悔
* @description Demo01---单个字符读取
* @date 2021/1/25 17:54
*/
public class Demo01 {
public static void main(String[] args) throws IOException {/*
public int read()
throws IOException
从这个输入流读取一个字节的数据。此方法继承类 InputStream
结果下一个数据字节,或 -1如果到达文件的结尾。*/
//创建文件输入流对象,指明读取的文件名
FileInputStream fis=new FileInputStream("month1.day.02\\a.text");
/*//将read()方法读取的字符转字节给len
int len= fis.read();//97
System.out.println(len);
len= fis.read();//98
System.out.println(len);
len= fis.read();//88
System.out.println(len);
len= fis.read();//100
System.out.println(len);
len= fis.read();//101
System.out.println(len);
len= fis.read();//-1 ,到目标文件的末尾
System.out.println(len);
len= fis.read();//再次读取依然会是-1
System.out.println(len);*/
//看到上面读取过程是步骤重复的过程,且不知道循环次数,故用循环whlie
int len=0;
while ((len= fis.read())!=-1)
{
System.out.println(len);
}
fis.close();
}
}
单个字节读取 的原理
一次读取多个字节的原理
package file.FileInputStreamDemo;
import java.io.FileInputStream;
import java.io.IOException;
/**
* @author 不悔
* @description Demo02--一次读取多个字节
* @date 2021/1/25 18:22
*/
public class Demo02 {
public static void main(String[] args) throws IOException {
//创建输入流对象,指明读取的目标文件
FileInputStream fis=new FileInputStream("month1.day.02\\a.text");
/*
//创建数组,指明每次读取的字节数
byte[] bytes=new byte[2];//每次读取两个字节
int len= fis.read(bytes);
System.out.println(len);//2
*/
/*
方法String(byte[] bytes)
通过使用平台的默认字符集解码指定的字节数组构造了一个新的 String
字符串是常量,它们的值不能被创建后改变。支持可变字符串字符串缓冲区。因为字符串对象是不可改变的,所以它们可以被共享。例如:
String str = "abc";
相当于:
char data[] = {'a', 'b', 'c'};
String str = new String(data);
*//*
//打印出数组中的字节,字节转字符串
System.out.println(new String(bytes));//ab
len= fis.read(bytes);
System.out.println(len);//2
System.out.println(new String(bytes));//cd
len= fis.read(bytes);//
System.out.println(len);//1
System.out.println(new String(bytes));//ed ,说明是头插法
*/
//观察发现,上面有重复,可以用循环,且不知道循环次数,所以用while
byte[] bytes=new byte[1024];//一般为1024的整数倍
int len= 0;
while ((len= fis.read(bytes))!=-1){
System.out.println(len);
System.out.println(new String(bytes));
}
}
}
用字节输入输出流复制粘贴文件的原理
字符串数组转字符串:
方法String(byte[] bytes)
通过使用平台的默认字符集解码指定的字节数组构造了一个新的 String
字符串是常量,它们的值不能被创建后改变。支持可变字符串字符串缓冲区。因为字符串对象是不可改变的,所以它们可以被共享。
String(byte[] bytes ,offset:起始位置 ,转换长度);
例子:
package file.fileinputstreamandfileoutputstream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
/**
* @author 不悔
* @description Demo01--字节流复制图片
* @date 2021/1/25 20:06
*/
public class Demo01 {
public static void main(String[] args) throws IOException {
//创建输入流对象
FileInputStream fis=new FileInputStream("D:\\桌面\\图片\\01.jpg");
//创建输出流对象
FileOutputStream fos=new FileOutputStream("D:\\桌面\\java相关APP\\01.jpg");
//读取目标文件
byte[] bytes=new byte[1024];
int len=0;
//写出目标文件
while ((len= fis.read(bytes))!=-1){
fos.write(bytes);
}
//先关闭写,再关闭读(写完了,读一定完了,读完了不一定写完了)
fos.close();
fis.close();
}
}
测试程序执行的时间:
long s=System.currentTimeMillis();
// 想测试时间的程序
long e=System.currentTimeMillis();
System.out.println(s-e);
字符
使用字节流读取文件时会遇到中文字符不能显示的问题,这是需要字符流来专门处理文本文件。(因为一个中文汉字可能占占两个或三个字节(分系统),但都是字符流一次读写一个字符,不管这个字符是中文字符还是英文字符)
字符输入流
package file.fileReader;
import java.io.FileReader;
import java.io.IOException;
/**
* @author 不悔
* @description Demo01--字符输入流
* 步骤跟字节输入流是一样的:
* 先创建字符输入流对象,绑定文件数据源
* 再调用read()方法读取数据
* 释放资源
* @date 2021/1/26 12:06
*/
public class Demo01 {
public static void main(String[] args) throws IOException {
FileReader fr = new FileReader("month1.day.02\\a.text");//括号里的都跟字节流一样,只是调用的对象不一样
/*
// 先创建字符输入流对象,绑定文件数据源
//调用reader方法,读取数据,存入内存fr.read();
int len = 0;
while ((len = fr.read()) != -1) {
System.out.print((char) len);
}
//释放资源
fr.close();
*/
char[] bytes=new char[10240000];//注意这里是char类型
int len=0;
while ((len= fr.read(bytes))!=-1){//read()方法里的值不要忘记了
System.out.println(new String(bytes,0,len));//String(char[] char)分配一个新的 String,它代表了目前包含在字符数组参数字符序列。(换句话说字符数组转字符串)
//String(char[] char ,offset:起始位置 ,转换长度);
}
//释放资源
fr.close();
}
}
字符数组转字符串:
String(char[] char)分配一个新的 String,它代表了目前包含在字符数组参数字符序列。(换句话说字符数组转字符串)
String(char[] char ,offset:起始位置 ,转换长度);
字符输出流
方法write().类比字节输出流,除了对象不一样,其他完全一摸一样。
package file.fileWriter;
import java.io.FileWriter;
import java.io.IOException;
/**
* @author 不悔
* @description Demo01--输出流(写出)
* @date 2021/1/26 13:13
*/
public class Demo01 {
public static void main(String[] args) throws IOException {
//创建输出流对象,指明数据源
FileWriter fw=new FileWriter("month1.day.02\\b.text");
//创建数组
char[] bytes={'1','我'};
//写出数据
fw.write(bytes);
fw.write("\r\n");
fw.write("我是巴巴变");
fw.write("我是巴巴变",1,2);
//关闭资源
fw.close();
}
}
关闭刷新的区别
刷新:执行后还可以继续使用
释放资源(关闭):执行后,不能继续读取或写入数据。
续写和换行,跟字节流一摸一样。(不过多赘述)
IO异常处理
JDK前的处理模板(有finally)(步骤)
例子:
发现依然报错,因为fw.close(),依然有可能出错,这时就在再finally内部再来一个try catch(学会这招)
改下面显示框的异常(优化)
找到显示框的异常类型,对异常类型做出优化(优化是指减少有可能出现错误的步骤,对有可能的出错的异常步骤做升级,使之一定不错)
上面发现加个,if(fw!=null)后明显的减少了异常出现概率
JDK7的新特性(步骤)(推荐)
例子:
JDK9的新特性(步骤)
(不怎么好,因为它既有trowns又有try catch)
代码实现:
package file.FileOutstreamdemo;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
/**
* @author 不悔
* @description Demo03---文件输出流的续写和换行
* @date 2021/1/25 16:54
*/
public class Demo03 {
/*
public FileOutputStream(String name,
boolean append)
throws FileNotFoundException
创建一个文件输出流,用指定的路径写入文件。如果append= true,然后字节将被写入到文件的末尾而不是开头(实现续写,不改变程序,再运行一遍也会直接在后面续写)。
*/
public static void main(String[] args) throws FileNotFoundException {
//JDK7前的try{可能出现异常的代码} catch(异常对象){打印异常} finally{必须要做的代码}
//未异常处理前
/*FileOutputStream fos=new FileOutputStream("month1.day.02\\a.text",true);//在本文件夹下的,可以在左侧目录看到
fos.write("你好".getBytes());
fos.write("你好".getBytes());
*//*windows 换行为"\r\n"
* linux:/n
* mac: /r*//*
fos.write("\r\n".getBytes());//想要换行,直接加一个这个语句
fos.write("你好".getBytes());
fos.write("你好".getBytes());
fos.write("你好".getBytes());
fos.close();*/
//异常处理
/* try {
FileOutputStream fos = new FileOutputStream("month1.day.02\\a.text", true);//在本文件夹下的,可以在左侧目录看到
fos.write("你好".getBytes());
fos.write("你好".getBytes());
*//*windows 换行为"\r\n"
* linux:/n
* mac: /r *//*
fos.write("\r\n".getBytes());//想要换行,直接加一个这个语句
fos.write("你好".getBytes());
fos.write("你好".getBytes());
fos.write("你好".getBytes());
} catch (IOException e) {
System.out.println(e);
} finally {
fos.close();
}*/
//遇到可学习的错误
/* FileOutputStream fos=null;
try {
fos = new FileOutputStream("month1.day.02\\a.text", true);//在本文件夹下的,可以在左侧目录看到
fos.write("你好".getBytes());
fos.write("你好".getBytes());
*//*windows 换行为"\r\n"
* linux:/n
* mac: /r *//*
fos.write("\r\n".getBytes());//想要换行,直接加一个这个语句
fos.write("你好".getBytes());
fos.write("你好".getBytes());
fos.write("你好".getBytes());
} catch (IOException e) {
System.out.println(e);
} finally {
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}*//*
// 做优化
FileOutputStream fos=null;
try {
fos = new FileOutputStream("month1.day.02\\a.text", true);//在本文件夹下的,可以在左侧目录看到
fos.write("你好".getBytes());
fos.write("你好".getBytes());
*//*windows 换行为"\r\n"
* linux:/n
* mac: /r *//*
fos.write("\r\n".getBytes());//想要换行,直接加一个这个语句
fos.write("你好".getBytes());
fos.write("你好".getBytes());
fos.write("你好".getBytes());
} catch (IOException e) {
System.out.println(e);
} finally {
if(fos!=null)
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}*/
// JDK7特性
// try(定义流对象,定义流对象....){可能出现异常的代码} catch(异常对象){打印异常}
try (FileOutputStream fos =new FileOutputStream("month1.day.02\\a.text",true)
){
fos.write("你好".getBytes());
fos.write("你好".getBytes());
/*windows 换行为"\r\n"
* linux:/n
* mac: /r*/
fos.write("\r\n".getBytes());//想要换行,直接加一个这个语句
fos.write("你好".getBytes());
fos.write("你好".getBytes());
fos.write("你好".getBytes());
fos.close(); }
catch(IOException e){
e.printStackTrace();
}
///JDK9新特性
// 定义流对象1,定义流对象2.... try(流对象1;流对象2){可能出现异常的代码} catch(异常对象){打印异常}
FileOutputStream fos=new FileOutputStream("month1.day.02\\a.text",true);
try(fos){//流对象中间以;相隔
fos.write("你好".getBytes());
fos.write("你好".getBytes());
/*windows 换行为"\r\n"
* linux:/n
* mac: /r*/
fos.write("\r\n".getBytes());//想要换行,直接加一个这个语句
fos.write("你好".getBytes());
fos.write("你好".getBytes());
fos.write("你好".getBytes());
fos.close();
}
catch(IOException e) {
e.printStackTrace();
}
}
}
总结:
字节输入输出流与字符输入输出流的使用是一样的,方法都是read(),write().步骤也都是先创建对应流对象,指明目标源,读取或者写出,释放资源。其中的字符数组,字节数组转字符串的String()方法也应该学习,学习怎么再API中查询构造方法,使用方法。同时优化,异常等都可以学习方法,同时利用这些方法,可以做到提高自己的学习能力,自学能力,这里我学到是:现在API中找对应方法,看构造方法,根据构造方法知道怎么创建对象,然后找不同方法,根据普通方法,知道怎么用这些普通方法区实现自己想要的功能,可以看自己想看的API的父类和同级别的子类,拓宽自己的能力范围。同时,上面只是文件的字节,字符输入输出流。
内部类
//内部类分为成员内部类、局部内部类、静态内部类、匿名内部类。
/*
* 成员内部类:在类里还有一个类,外面的类叫外部类,内部的类叫内部类,外部类可以访问调用内部类的方法和变量,内部类也能访问调用外部类的方法和变量
* 测试类调用成员内部类的创建对象的语法格式:外部类名.内部类名 变量名=new 外部类名().new 内部类名();
* 局部内部类:外部类方法里的类,局部内部类可以访问调用外部内部类的变量和方法,但是局部内部类的方法和变量只能在创建该局部内部类的方法中进行访问调用,类似于成员变量,作用域在创建它的方法里。
* 在创建局部内部类的方法中调用局部内部类的具体语法格式: 局部内部类 变量名=new 局部内部类();–与正常实例化一样
* 静态内部类:用static修饰的成员内部类,静态内部类中只能访问外部类的静态成员,测试类同时通过外部类,访问静态内部类成员时,可以跳过外部类从而直接通过内部类访问静态内部类成员
* 测试类调用静态内部类的创建对象的语法格式: 外部类名.静态内部类名 变量名=new 外部类名.静态内部类名();
* 匿名内部类:在测试类中调用某个方法时,如果方法参数时一个接口类型,除了传入一个接口实现类,还可以使用匿名内部类来实现接口,作为该方法的参数,所以匿名内部类相当于接口的实现类,在匿名内部类中直接完成接口中抽象方法的实现
* 测试类方法调用某接口参数如方法test(X接口类型 参数名)–>test(new X(){匿名内部类实现部分(接口方法实现)});*/
泛型:
https://www.runoob.com/java/java-generics.html
加<?>具体泛型会限制范围,还注意int等类型在泛型中必须全称如integer,Double,Character还有Number类型等,否则会报错
实用类
String
使用 == 和 equals() 比较字符串。
String 中 == 比较引用地址是否相同,equals() 比较字符串的内容是否相同
什么情况会有地址相同的时候呢,当公共池里已经存在一个对象,现在重新定义一个内容与公共池里这个对象内容相同的对象,且这个对象也是加入公共池,则加入时会先在池中查看有无此相同内容,有的它不会创建新的对象,而是引用这个对象,这个时候地址相同,没事时创建新的对象。
String s1 = "Hello"; // String 直接创建
String s2 = "Hello"; // String 直接创建
String s3 = s1; // 相同引用
String s4 = new String("Hello"); // String 对象创建
String s5 = new String("Hello"); // String 对象创建
s1 == s1; // true, 相同引用
s1 == s2; // true, s1 和 s2 都在公共池中,引用相同
s1 == s3; // true, s3 与 s1 引用相同
s1 == s4; // false, 不同引用地址
s4 == s5; // false, 堆中不同引用地址
s1.equals(s3); // true, 相同内容
s1.equals(s4); // true, 相同内容
s4.equals(s5); // true, 相同内容
用数据类型的形式定义的变量进入字符串池(公共池)如String b;,而以new 定义的变量是创建一个新的栈来储存字符串如String a=new String();。
“a”+"b"字符串相加的时候,都是静态字符串的结果会添加到字符串池,如果其中含有变量(如String e=“b” String f=“a”+e)则不会进入字符串池中。但是字符串一旦进入字符串池中,就会先查找池中有无此对象。如果有此对象,则让对象引用指向此对象。如果无此对象,则先创建此对象,再让对象引用指向此对象
Java intern() 方法规范字符串,方式是查看字符池内容。
正则表达式
什么是正则表达式:
正则表达式是对字符串操作的一种逻辑公式,就是用事先定义好的一些特定字符、及这些特定字符的组合,组成一个"规则字符串",这个"规则字符串"用来表达对字符串的一种过滤逻辑(匹不匹配)。给定一个正则表达式和另一个字符串,我们可以达到如下的目的:
- 给定的字符串是否符合正则表达式的过滤逻辑(称作"匹配");
-
可以通过正则表达式,从字符串中获取我们想要的特定部分。(知道有没有对应字符呀,知道模式字符在那个位置呀)
例子
校验QQ号,要求:必须是5~15位数字,0不能开头。没有正则表达式之前
public class regex {
public static void main(String[] args) {
checkQQ("0123134");
}
public static void checkQQ(String qq)
{
int len = qq.length();
if(len>=5 && len <=15)
{
if(!qq.startsWith("0"))
{
try
{
long l = Long.parseLong(qq);
System.out.println("qq:"+l);
}
catch (NumberFormatException e)
{
System.out.println("出现非法字符");
}
}
else
System.out.println("不可以0开头");
}
else
System.out.println("QQ号长度错误");
}
}
使用正则表达式之后的代码:
public class regex {
public static void main(String[] args) {
checkQQ2("0123134");
}
public static void checkQQ2(String qq) {
String reg = "[1-9][0-9]{4,14}";
System.out.println(qq.matches(reg)?"合法qq":"非法qq");
}
}
正则表达式的特点是:
- 灵活性、逻辑性和功能性非常的强;
- 可以迅速地用极简单的方式达到字符串的复杂控制。
- 对于刚接触的人来说,比较晦涩难懂。
注意:正则表达式写好后,没有错对之分,返回结果只是true和false
在其他的语言中(如Perl,c),一个反斜杠 \ 就足以具有转义的作用,而在 Java 中正则表达式中则需要有两个反斜杠才能被解析为其他语言中的转义作用。也可以简单的理解在 Java 的正则表达式中,两个 \ 代表其他语言中的一个 \,这也就是为什么表示一位数字的正则表达式是 \d,而表示一个普通的反斜杠是 \\
模式and匹配
pattern :正则表达式的编译表示。
matcher:匹配器是通过调用模式的matcher方法从模式创建(如 Matcher m = p.matcher(INPUT); // 获取 matcher 对象
)。一旦创建,匹配器可用于执行匹配操作三种不同.
appendReplacement 方法:sb 是一个 StringBuffer,replaceContext 待替换的字符串,这个方法会把匹配到的内容替换为 replaceContext,并且把从上次替换的位置到这次替换位置之间的字符串也拿到,然后,加上这次替换后的结果一起追加到 StringBuffer 里(假如这次替换是第一次替换,那就是只追加替换后的字符串啦)。
appendTail 方法:sb 是一个 StringBuffer,这个方法是把最后一次匹配到内容之后的字符串追加到 StringBuffer 中。
两个方法一起使用就可以达到所有替换或者替换第一个
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class RegexMatches
{
private static String REGEX = "a*b";
private static String INPUT = "aabfooaabfooabfoobkkk";
private static String REPLACE = "-";
public static void main(String[] args) {
Pattern p = Pattern.compile(REGEX);
// 获取 matcher 对象
Matcher m = p.matcher(INPUT);
StringBuffer sb = new StringBuffer();
while(m.find()){
m.appendReplacement(sb,REPLACE);
}
m.appendTail(sb);//当没有这一步时,结果不会有kkk232232131
System.out.println(sb.toString());
}
}
-foo-foo-foo-kkk
替换字符串中的一个单个字符用public String replace(char searchChar, char newChar)方法
多个字符也可用这个方法,其实这个方法的实质还是正则表达式
public class Main {
public static void main(String args[]) {
String Str = new String("Runoob");
System.out.print("返回值 :" );
System.out.println(Str.replace('o', 'T'));
System.out.print("返回值 :" );
System.out.println(Str.replace('u', 'D'));
}
}
返回值 :RunTTb
返回值 :RDnoob
替换字符串中的多个字符用正则表达式中的replaceFirst 和 replaceAll 方法,也可用String的replace方法的
replaceFirst 和 replaceAll 方法用来替换匹配正则表达式的文本。不同的是,replaceFirst 替换首次匹配,replaceAll 替换所有匹配。
下面的例子来解释这个功能:
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class RegexMatches
{
private static String REGEX = "dog";
private static String INPUT = "The dog says meow. " +
"All dogs say meow.";
private static String REPLACE = "cat";
public static void main(String[] args) {
Pattern p = Pattern.compile(REGEX);
// get a matcher object
Matcher m = p.matcher(INPUT);
INPUT = m.replaceAll(REPLACE);
System.out.println(INPUT);
}
}
The cat says meow. All cats say meow.
可以简写为
public static void main(String[] args) {
System.out.println(Pattern.compile("dog").matcher("dog and dog is wang wang").replaceAll("catw"));
}