数组
定义以及赋值
int[] arr={1,2,3};
int[] arr=new int[]{1,2,3};
int[] arr=new int[3]; //没有赋值,int类型默认元素为0,string类型默认元素null
遍历
for循环
for (int i=0;i< arr.length;i++){
System.out.println(arr[i]);
}
foreach循环
for (int i:arr) {
System.out.println(i);
}
Arrays工具类
System.out.println(Arrays.toString(arr)); //[1, 2, 3]
内存分析
java数组的类型是引用类型数据,因此定义它要用java的关键字new。可以省略new关键字是因为JVM先识别int[]是一个数组,然后自动调用执行new关键字的操作,简写的本质上仍然使用了new关键字
数组的定义中当执行到new关键字时,JVM调用了数值元素类型对应的构造器的方法来实例化:
- 开辟内存空间,根据数组类型和元素个数向操作系统申请对应的内存空间
- 调用构造器并初始化,堆内存的大小
- 将生产的地址返回,将堆内存中分配得到的地址保存到栈内存对应分配得到的单元空间里
arr={1,2,3}; //arr→堆内存,{1,2,3}→栈内存
方法
定义
public static void main(String[] args){}
权限修饰符 静态修饰符 返回值类型 方法名(形式参数:(数据类型 变量名)){
返回值类型不是void: return 返回具体结果;
void关键字: 没有返回值
}
方法的重载
如果有两个方法的方法名相同,但参数不一致,可以说一个方法是另一个方法的重载。注意:
- 方法名相同
- 方法的参数类型、参数个数,要么类型不一样,要么个数不一样,要么都不一样
- 方法的返回类型可以不同
- 方法的修饰符可以不同
- main方法也可以被重载
构造方法
构造函数是一种特殊的函数,可以通过调用构造函数来创建一个对象或类的实例
构造函数的写法
- 和类名称相同
- 不含返回值类型,不能用return返回一个值(不含返回值≠返回值类型为void,void也不能写)
- 一般访问权限为public
java中每个类至少要有一个构造方法,如果自己没有在类里定义构造方法,系统会自动为这个类产生一个默认的构造方法
public class Test1 {
public Test1() {
//默认构造器
}
}
可以通过构造函数来完成对成员变量的初始化
toString()方法同样可以在source中快捷生成
如果没有toString方法,只会打印出地址
注意:一旦自己显示的写出了有参数的构造方法,也要显示的写出无参数的空构造。因为一旦编程者定义了构造方法系统就不会生成默认的构造方法,而开发用的框架一般会调用类的空构造。构造方法也可以重载,可以有多个构造方法
类和对象
面向对象
面向对象的基本特质
- 封装性
- 抽象性
- 继承性:没有多重继承,但是可以通过单重继承+接口的方式实现多重继承
- 多态性
类class——对某一类事物的描述
对象object——是实际存在的某类事物的个体,也成为实例instance
类的构成
类是数据以及对数据的一组操作的封装体
- 成员变量
- 成员方法
- 构造方法
类
声明格式
[public] [abstract|final] class 类名称 [extends 父类名称] [implements 接口名称列表]{
成员变量声明及初始化;
方法声明及方法体;
}
- static:修饰的属性可以通过 类名.属性名 获取到属性的值
访问修饰符
- 默认:不同包无法访问
- public:不同包可以访问
- final:不能由这个类派生出其他的子类,这个类不能被继承
- abstract:抽象类
变量
声明格式
[public|protected|private] [static] [final] 变量数据类型 变量名1[=变量初值],变量名2[=变量初值],...;
- static:静态成员变量
- final:变量的值不能被修改
访问修饰符
- public:公开,同类、同包、子类、不同包均可访问
- protected:受保护,同类、同包、子类可访问,不同包不可访问
- private:私有,只有同类可访问
类的方法
声明格式
[public|protected|private] [static] [final] [abstract] [native] [synchronized] 返回类型 方法名([参数列表]) [throws exceptionList]{
方法体;
}
- static:指明是一个类方法
- final:指明是一个终结方法
- abstract:抽象方法
- native:用来集成java代码和其他语言的代码
- synchronized:用来控制多个并发线程对共享数据的访问
访问修饰符:和变量的相同
eclipse有快捷方式 source->gets and sets可以快速生产get和set方法,ctrl+shift+f格式化
修饰符
-
privae:不被外部类访问
-
protected:子类可以访问父类的,是父类传递给子类的继承信息
-
public:所有类可以访问
-
无修饰词:表示包访问权限(相当于c++的友元) ,同一个包内可以访问,访问权限是包级访问权限;比 protected大,比public小。但是有些公司规范规定不能使用默 认修饰符
instanceof对象运算符
对象运算符instanceof 判断一个对象是否属于指定类及 其子类,返回boolean类型
Time1 t=new Time1( );
t instanceof Time1; //返回true,t是Time1类的实例
this引用
Java类中的每个成员方法都可以使用代词this引用调用 该方法的当前对象自己
- 指代对象本身
- 访问本类的成员变量和成员方法
一个成员方法中,若没有与成员变量同名的局部变量或形式参数,则this引用可以省略。当局部变量或形式参数与成员变量同名时,方法体中默认的是局部变量或形式参数,而要访问成员变量必须使用this
类的成员方法的参数
-
形参为普通简单量时,采用传值的方式
-
形参为对象变量时,采用是传引用的方式
参数传值
适用范围:8种基本数据类型:boolean , byte , char ,short , int ,long ,float ,double;String对象
特点:在内存中复制一份数据,把复制后的数据传递到 方法内部
作用:在方法内部改变参数的值,外部数据不会跟着发 生改变
参数传引用
适用范围:数组、除String以外的其他所有类 型的对象,StringBuffer动态字符串是传引用
特点:将对象的地址传递到方法内部
作用:在方法内部修改对象的内容,外部数据也会跟着发生改变
对象
格式
类名 对象名=new 构造函数
构造函数是面向过程中的叫法,在面向对象里是构造函数,其实是一个概念,名称必须是类名
匿名对象
new Person().sayHello(); //Hello null
如果对一个对象只需要进行一次方法调用,可以采用匿名对象
对象创建的内存模型
java中的数据类型
- 基本数据类型:四类八种——boolean、byte、char、short、int、long、double、float
- 引用类型变量:类、接口、数组
继承
extends
一个类成为某个类的子类,那么它就会继承这个父类的部分属性和方法。增强代码的可重复性、复用性
关键字extends
[类修饰符] class 子类名 exetends 父类名{
语句;
}
java.lang.Object类是所有java类的最高层父类,是唯一一个没有父亲的类。如果在类的声明中未使用extends关键字指明父类,则默认父类为Object类,java中类的继承形成了以Object为树根的树状层次结构
java中只允许单继承,一个类最多只能显示地继承一个父类,一个类可以被多个类继承
子类继承父类的
- 成员变量:能继承public和protected的,不能继承private修饰的成员变量。隐藏现象,子类成员变量会屏蔽掉父类中的同名成员变量,如果要在子类中访问父类中同名变量,需要用super关键字来引用
- 方法:同样不能继承private的方法。在子类中出现与父类同名同参数的方法,则会覆盖(方法重写),想调用父类的同样要super
区分重写(与父类一模一样)与重载(与父类中方法同名但参数不同)
super
子类不能继承父类的构造器,如果父类的构造器带参数,必须在子类的构造器中显示的通过super关键字调用父类的构造器并配以适当的参数列表。如果父类有无参构造器,则不必须用super调用父类构造器。如果没有super关键字,系统会自动调用父类的无参构造器
super用法
- 在子类中调用父类的同名成员变量/方法,格式:super.成员变量/方法
- 在子类的构造器中显示地调用父类的构造器,格式:super(parameter1,parameter2,…),必须放在子类构造器中的第一个语句
多态
java有两种引用类型:编译时类型、运行时类型。编译时类型由声明这个变量的时候决定,运行时类型由实际赋值来决定,当编译时类型和运行时类型不一致时,就可能出现多态
将子类对象赋值给父类类型的对象——子类的向上转型。向上转型会丢失子类里特有的方法(也就是上面截图的fun1)
指向子类的父类引用由于向上转型了。它只能访问父类拥有的方法和属性,而子类中存在父类中不存在的方法,该引用是不能使用的,尽管是重载方法。若子类重写了父类中的某些方法,在调用这些方法的时候,必定是使用子类中定义的这些方法,他们优先级高于父类中的方法
实现机制
基于继承、接口的多态机制主要表现在父类和继承该父类的一个或多个子类对某些方法的重写,多个子类对同一方法的重写可以表现出不同的行为。
多重继承的例子
在继承链当中对象方法的调用存在优先级:this.show(O)、super.show(O)、this.show((super) O)、super.show((super) O)
当父类对象引进用变量引用子类对象时,被引用的对象决定了调用谁的成员方法(上图new后面的类),但是这个被调用的方法必须是在父类中定义过的,不能是子类中的特有方法
上图中的a2.show(b):
抽象类
public abstract class Animal{
public abstract void bark();
}
abstract关键字,没有方法体,就叫抽象方法。(而在子类中有根据具体情况对该方法的重写)
类中有抽象方法,则类名也需加关键字。
-
抽象方法注意用public或protected修饰,不要用private,不然子类不能继承
-
抽象类不能定义对象,如下面针对上面类
public class Test{
public static void main(String[] args){
Animal animal=new Animal();//会报错
}
}
- 如果一个类继承一个抽象类,那么子类必须实现父类的抽象方法。否则子类继承的方法还是抽象方法,子类也变成抽象类,要用abstract修饰
接口
在Java编程语言中是一个抽象类型,是抽象方法的集合,通常以Interface来声明。一个类通过继承接口的方式,从而来继承接口的抽象方法。
接口不是类,编写接口的方式和类很相似,但是他们属于不同的概念。类描述对象的属性和方法,接口则必须包含类要实现的的方法。除非实现接口的类是抽象类,否则该类中要定义接口中的所有方法。
接口无法被实例化,但是可以被实现。一个实现接口的类,必须实现接口内所描述的所有方法,否则就必须声明为抽象类。另外,在Java中,接口类型可以用来声明一个变量,但基本没什么意义。
抽象类里有可以不实现的方法(抽象方法,存在目的是让继承抽象类的子类去实现的),当然也可以有普通实现了的方法。但是接口里所有的类都必须是抽象方法,所以可以把接口理解为比抽象类更加抽象的一种类型,它的存在就是为了给实现接口的“子类”出现的。(类似子类与父类关系,但是实现接口不是真正的子类)
新建文件时选Interface不要选java文件
public interface InterfaceTest {
public void test1();//没必要加abstract关键字,默认抽象方法
public String test2();
}
接口相当于定义了一个规则
实现接口
类实现接口用implements关键字而不是继承的关键字,
public class Main implements InterfaceTest{
@Override
public void test1() {
// TODO Auto-generated method stub
}
@Override
public String test2() {
// TODO Auto-generated method stub
return null;
}
}
必须实现接口中的抽象方法,否则会报错
jdk 1.8以后特性
default void test3() {}
在接口中用default关键字增加新方法,可以不用在实现接口的类中新增这个方法,就省去了修改
多接口
接口可以实现多个接口,中间用逗号隔开。而继承只能继承一个
内部类
一个类定义在另一个类内部
public class OuterClass {
private String name;
private int age;
class InnerClass{
public InnerClass() {
name="Alice";
name="18";
}
}
}
内部类可以直接访问外部类的,哪怕是private
编译后会形成两个.class(但是代码中在一个类中)
成员内部类
成员内部类是最普通的内部类,它是外围类的一个成员,可以无限制的访问外围类的所有成员属性和方法,尽管是private的,但是外围类访问内部类的成员属性和方法需要通过内部类实例来访问
注意:
- 成员内部类中不能存在任何static的变量和方法
- 成员内部类是依附于外部类的,所以只有先创建了外围类才能够创建内部类
例子:
public class OuterClass {
private int id;
private String name;
public class InnerClass{
//public static int iidd;//会报错,成员内部类不允许定义静态成员
public void innermm() {
id = 18;
name = "lyris";
System.out.println(id);
System.out.println(name);//成员内部类可以无障碍的访问外部类成员
}
}
}
public class Main {
public static void main(String args[]) {
OuterClass outerClass = new OuterClass();
OuterClass.InnerClass innerClass = outerClass.new InnerClass();
innerClass.innermm();//打印出18 (换行) lyris
}
}
以上可以实现但是不实用,一般用get方法
public InnerClass getInnerClass() {//在外部类里写一个相关get方法
return new InnerClass();
}
效果一致但是推荐该写法
局部内部类
嵌套在方法的方法体内,对于这个类的使用主要是应用与解决比较复杂的问题,想创建一个类来辅助我们的解决方案,又不希望这个类是公共可用的,所以就产生了局部内部类,局部内部类和成员内部类一样被编译,只是它的作用域发生了改变,它只能在该方法中被使用,出了该方法就会失效。
一般与接口混合使用
例子:
//OuterClass.java
public class OuterClass {
private int id;
private String name;
public void outermm() {
class InnerClass implements InnerInterface{
@Override
public String iimm() {
// TODO Auto-generated method stub
return "这是InnerClass这个局部内部类里的InnerInterface接口中定义的抽象方法iimm";
}
}
InnerClass innerClass = new InnerClass();//使用局部内部类
String str = innerClass.iimm();
System.out.println(str);
}
}
//接口InnerInterface.java
public interface InnerInterface {
public String iimm();
}
//Main.java
public class Main {
public static void main(String args[]) {
OuterClass outerClass = new OuterClass();
outerClass.outermm();
}
}//打印这是InnerClass这个局部内部类里的InnerInterface接口中定义的抽象方法iimm
匿名内部类
静态内部类
异常
异常处理
检查异常、非检查异常
处理检查异常
- 利用try…catch…finally语句块处理
- 在函数签名中使用thorws声明交给函数调用者caller去解决
利用try-catch包裹可能出现异常的部分
try{
FileInputStream f=new FileInputStream("a.txt");
}catch (FileNotFoundException e){
e.printStackTrace();//打印异常信息
System.out.println("Can't find");
}
注意
-
try块中的局部变量和catch块的局部变量(包括异常变量),以及finally中的局部变量,他们之间不可共享使用
-
每一个catch块用于处理一个异常,异常匹配是按照catch块的顺序从上往下寻找的,只有第一个匹配的catch会得到执行
-
多个catch时范围必须是从小到大,也就是上面是子类下面是父类
-
java中,异常处理的任务就是将执行控制流从异常发生的地方转移到能处理这种异常的地方去
类throws FileNotFoundException将异常往上丢,交给调用者解决
public static void main(String[] args) throws FileNotFoundException{}
这里main是被虚拟机调用的所以虚拟机处理异常,会直接报错
throw
不是throws!!!
手动抛出异常
throw new RuntimeException("Time error");
//Exception in thread "main" java.lang.RuntimeException: Time error
I/O流
在Java中,把不同类型的输入、输出源(键盘、文件、网络等)抽象为流 (Stream)
文本文件(.txt、.java、.c、.cpp)使用字符流,非文本文件(.jpg、.mp3、.avi、.doc、.ppt)用字节流
体系
分类
-
输入流、输出流
-
字节流(8 bit)、字符流(16 bit)
-
节点流、过滤器(处理流)
字符流不能处理图片等字节数据
节点流(或文件流)
read(byte[] buffer); //InputStream
write(byte[] buffer,0,len);//OutputStream
read(char[] buffer); //Reader
write(char[] buffer,0,len);//Writer
缓冲流(处理流一种)
read(byte[] buffer); //BufferedInputStream
write(byte[] buffer,0,len); //BufferedOutputStream
read(char[] buffer);readLine();//BufferedReader
write(char[] buffer,0,len); //BufferedWriter
字符流
Reader
File类具有查询文件属性、状态和文件名等功能,但不能访问文件内容
相对路径
public static void main(String[] args) {
//C:\Users\HanYiting\IdeaProjects\TestFile\src\hello.txt
File file=new File("src\\hello.txt");//相对于当前工程
System.out.println(file.getAbsoluteFile());
}
public static void TestFileReader(){
File file=new File("hello.txt");//相对于当前model
}
FileReader读入数据
public static void TestFileReader() throws IOException {
File file=new File("src\\hello.txt");//实例化File类的对象
FileReader fr=new FileReader(file);//提供具体的流
int data;//read()返回值为int类型,返回读入的一个字符,没有则返回-1
while((data=fr.read()) != -1){
System.out.print((char)data);
}
if(fr != null) fr.close();
}
垃圾回收机制中,对于物理上的连接,如数据库连接、输入输出流连接,Socket连接不能自动关闭,需要手动关闭输入输出流
选中后ctrl+Alt+T快捷键可选择try/catch/finally快速做异常处理 ↓
public static void TestFileReader(){
FileReader fr= null;//提供具体的流
try {
File file=new File("src\\hello.txt");//实例化File类的对象
fr = new FileReader(file);
int data;
while((data=fr.read()) != -1){
System.out.print((char)data);
}
} catch (IOException e) {
e.printStackTrace();
} finally {}
try {
if(fr != null) fr.close();
} catch (IOException e) {
e.printStackTrace();
} finally {}
}
注意,fr.close()也要做异常处理
read的重载:read(char[] buf)的用法
char[] cbuf=new char[5];
fr.read(cbuf)//会5个5个读,没有则返回-1
/*int len;
char[] cbuf=new char[5];
while((len = fr.read(cbuf)) != -1){//
System.out.print(cbuf);
}helloworld123→helloworld123ld,因为最后只能读3个,没有新的字符可以覆盖后面两个字符*/
所以用的时候用String,然后每次输出注意截取String str=new String(cbuf,0,len)
Writer
public static void TestFileWriter() throws IOException {
File file=new File("hello1.txt");//没有则会默认创建一个
FileWriter fw=new FileWriter(file);//构造器还有参数FileWriter(file,true),true就不覆盖,在原有文件后追加
fw.write("Hei Boy");
fw.close();
}
write同样也有多个重载方法,详情去看定义
字节流
处理文本文件
public static void TestFileInputStream(){
File file=new File("src\\hello.txt");
FileInputStream fis=new FileInputStream(file);
byte[] buffer=new byte[5];
int len;
while((len=fis.read(buffer))!=-1){
String str=new String(buffer,0,len);
System.out.print(str);
}
fis.close();
}//再做一下异常处理
处理非文本文件
public static void FileStream(){
FileInputStream fis= null;
FileOutputStream fos= null;
try {
File srcFile=new File("src\\picture.png");
File destFile=new File("src\\1.png");
fis = new FileInputStream(srcFile);
fos = new FileOutputStream(destFile);
byte[] buffer=new byte[10];
int len;
while ((len=fis.read(buffer))!=-1){
fos.write(buffer,0,len);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if(fos!=null){
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
} finally {}
}
if(fis!=null){
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
} finally {}
}
}
}
缓冲流
缓冲是为了提高读写效率
造流先造内层再造外层,关的时候先关外层再关内层。关闭外层时,内层流会自动关闭,所以只写外层的close即可
public static void BufferedTest() throws IOException {//没改try-catch
File srcfile=new File("src\\hello.txt");
File destFile=new File("src\\hei.txt");
FileInputStream fis=new FileInputStream(srcfile);
FileOutputStream fos=new FileOutputStream(destFile);
BufferedInputStream bis=new BufferedInputStream(fis);
BufferedOutputStream bos=new BufferedOutputStream(fos);
byte[] buffer=new byte[10];
int len;
while ((len=bis.read(buffer))!=-1){
bos.write(buffer,0,len);
}
bos.close();
bis.close();
}
通过时间分别测试缓冲流和普通的字节流复制视频时间,缓冲流明显快
long start=System.currentTimeMillis();
...
long end=System.currentTimeMillis();
System.out.println(end-start);//缓冲流157,字节流9391
Buffer内部提供了一个缓冲区
也就是说缓冲区大小8192(=1024×8)
bos.flush();//刷新缓冲区,缓冲区满时会自动清空
可以通过匿名的方式简化
BufferedReader br=new BufferedReader(new FileReader(new File("src\\hello.txt")));
其他方法
String data;
data=br.eadLine();//BufferedReader,读取一行但不读取换行符,记得自己加\n,没有值时返回null
//bw.newLine();BufferedWriter的方法,换行用
final关键字
final——无法改变的量。对比于static静态变量——只有一份存储空间,值可以改变
如Math类中用final修饰
作用
- 修饰变量:被final修饰的变量必须要初始化,赋初值后不能再重新赋值(一般不讨论局部变量)
- 修饰方法:被final修饰的方法不能重写
- 修饰类:被final修饰的类,不能够被继承。final修饰的类,类中所有的成员方法都被隐式指定为final方法
final修饰变量
被final修饰的变量必须显示的初始化:定义时初始化/在构造器中设置值/在非静态块中为final实例变量设置值
public class Main {
final int a=10;//第一种
final int b;
final int c;
public Main() {//第二种
b=20;
}
{
c=30;//第三种
}
}
final指在栈内存中储存的值不可改变。限定引用数据类型,栈中存储的不是真实的值而是堆中地址,结果使得其在栈中储存的内存地址不可改变(值因为在堆中,可以变),即不可更改的是该变量不可以再指向别的对象
与static区别
static作用于成员变量用来表示只保存一份副本,而final作用保证变量不可变
两次打印的值一样