JAVA基础

1.面向对象

1.2内存分配

class A
{
    int i;
    int j;
}
class TestMemo
{
    public static void main(String[] args)
    {
        A aa = new A();
    }
}

​ new A()在内存中分配一片区域,被当作了A对象

​ aa本身的内存是在栈中分配的

​ 堆中内存的地址付给了aa

​ aa只想堆中的内存,aa代表了堆中的内存

2.继承

子类只能继承父类的非私有部分,私有部分无法继承,其实私下是继承过来了,只是不能访问。

所以继承要慎重,否者会浪费内存

class A{
	public i;
	private j;
	protected k;
	public void g{}
	private void k{}
	protected void v{}
}
class B extends A{
	i = 10;
	//j = 20; err  私有的属性不能被继承
	k = 30;
	g();
	//k();  err   私有的方法不能被继承
	v();
}

java支持单继承

关键字super

class
{
    //100个属性
    public A(){
    }
}
class B extends A{
    //20个属性
    super(100个值);
}

直接调用父类的构造方法

static 可以通过类名进行访问,但是能不能被访问还有看是不是非私有的

子类访问父类的三种方式

1.子类访问

2.子类的方法访问

3.子类的类名访问父类的成员(new 出一个子类,然后通过子类访问)

对父类的构造方法的继承可以通过super关键字

class A{
    public int i;
    public A(int i){
        this.i = i;
    }
}
class B extends A{
    public int j;
    public B(int i, int j){
        super(i);
        this.j = j;
    }
}

super不写的话,在子类默认的是调用无参的super();

总结:1.每个子类构造方法的第一条语句,都会隐含的调用super(),如果父类没有这种形式的构造参数,那么编译就会报错;

2.如果显示的写出super();语句,则必须保证该语句是第一条语句,否则会出错;

3.super();如果不写,则编译器会自动添加,所以此时父类没有无参的构造函数,就会报错

4.即可以写super();前提是父类必须有无参的构造函数,也可以显示写super(实参);前提是父类必须有带参的构造函数

5.调用父类的构造函数的语句必须借助于super,不能直接写父类的类名,

6.一个构造函数中不能写多个super(参数)语句;

方法的重写

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

1.子类通过和父类写一样的方法(方法名称、参数列表、返回值类型),会把父类的方法覆盖,也就是重写

2.子类中不允许出现与父类同名同参但是返回值不同的方法,编译器会报错

3.覆盖方法时,不能使用父类中被覆盖方法更严格的权限(原因在多态)

class demo1{
	public void hello(){
		System.out.println("hello");
	}
}
class demo2 extends demo1{
	private/public void hello(){		//此处应该的等级应该不小于父级的public
		System.out.println("wold");
	}
}
public class ExtendsTest{
	public static void main(String[] args) {
		System.out.println("ExtendsTest");
	}
}

Java中子类实例化,先调用的是父类的构造函数

class demo1{
		public static String name;
		public static int age;
		public demo1(){
			this.name = "demo1";
			this.age = 1;
		}
}
class demo2 extends demo1{
	public demo2(){
		this.name = "damo2";
		this.age = 2;
	}
}
public class ExtendsTest{
	public static void main(String[] args) {
		demo2 de = new demo2();
		System.out.println(demo2.name);//demo2 这里调用的是子类的构造方法
	}
}

super 方法用来调用父类的隐藏方法,或者被覆盖的方法,当子类的构造方法中写了super()时,子类实例化时会先调用子类的构造方法

Java中子类在实例化的时候调用父类的无参构造方法(转载)

super 可以带参数,也可以不带参数,对应会调用相应的父类构造器,如果子类构造器中没有显示地使用super 则系统默认调用无参数构造器。

父类是有参构造器,子类也是有参构造器(参数=父类形参+子类形参),用super(父类形参) 调用父类构造器,在new出来的子类实参个数对应子类的构造器的形参个数

3.抽象类和final

3.1.抽象类

抽象类不能实例化

通常用来作为一个类族的最顶层的父类,用最底层的类表示现实中的具体事物,用最顶层的类表示该类族所有事物的共性

abstract class A{
    public abstract void f();
}

抽象方法:

1.在定义Java方法时可以只给出方法头,而不给出方法内部的实现代码,这样的方法称为抽象方法

2.凡是没有方法体的方法必须使用abstract关键字修饰为抽象方法

3.凡是含有抽象方法的类必须声明为抽象类

抽象类:

1.用abstract关键字来修饰的一个类,叫抽象类;

2.包含抽象方法的类必须声明为抽象类

3.但是一个抽象类中却可以不包含任何抽象方法

abstract class A{
    abstract public void f();
}
class B extends A{
    public void f(){
        System.out.printf("BBBB");
    }
}
//这里的B类把A类的抽象方法实现了,所以前面不用在加abstract
public class demo{
    public static void main(String[] args){
        B bb = new B();
       // A aa = new A(); error
       //用多态
       A aa; //指向抽象类的指针
       aa = bb;
       aa.f();
    }
}

在抽象类中定义好所有的方法;具体实现可以在后面的子类

总结:(转载)

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

3.2.final

1.final可以修饰类、方法、域

修饰类则该类不能被继承,

修饰方法的变量是常变量(初始化,不能再被改变),

修饰变量时必须初始化;

4.接口

4.1.接口的规范

1.接口定义的属性必须是public static final的,而接口中的方法则必须是public abstract的,因此这些修饰符可以部分或者全部省略

省略之前:

public static final int i = 20;
public abstract void f();

省略后:

int i = 20;
void f();

2.接口定义的属性的值在实现类中不能被修改

interface It{
    int i = 10;
}
class A implements It{
    public A(int j){
        //this.i = j; err
    }
}
interface It2{
    int i = 20;
    void f();
}
class A implements It2{
    public void f(){
        i = 99;
        Syetem.out.printf("i = %d\n", i);
    }
}
//其中方法被重写后,A类前就不用写abstract抽象

4.一个类只能实现某个接口,不能继承某个接口

5.但接口可以继承接口

interface It1{}
interface It2{}
interface It3 extends It1, It2{}
public class C{
    public static void main(String[] args){}
}

6.接口不但可以继承接口,而且可以继承多个接口,即接口允许多继承

7.如果一个类只实现了一个接口的部分方法,则该类必须的声明为抽象类

看第二个的第二个代码

8.一个类可以在继承一个父类的同时实现一个或多个接口,但extend关键字必须要在implements之前

class T extends A implements It4,It3{}

9.不可以new接口对象,但可以定义一个接口引用类型的变量并将其指向实现接口的对象,达到多态的目的!

interface It{
    void f();
}
class A implements It{
    public void f(){
        System.out.printf("AAAA")
    }
}
class D{
    public static void main(String[] args){
        It it;
    }
}

一个类要实现一个接口中的方法,该方法返回值前必须要加public

实现部分方法的实现类必须是抽象类

4.2.接口的作用

1.通过接口可以实现不相关类的相同行为

Java.lang.Colneable接口是个空接口,目的是起到标识作用,所有能完成自我复制的类都必须实现

2.接口提供了不同对象进行协作的平台

如事件处理

3.接口可以实现多继承,从一定程度上弥补了类只能单继承的缺陷

4.接口是我们了解一个类功能的重要途径

5.异常

5.1.异常的使用方法

public class demo{
    public static void main(String[] args){
        try{
            int a = 3/2;
        }
        catch(ArithmeticException e){
            System.out.printf("出错");
        }
    }
}

一个代码只能抛出一个异常

为什么需要异常:对异常进行处理try{} catch(异常种类){}

public class TestExcep_3{
    public static void main(String[] args){
        int i;
        Scanner sc = new Scanner(System.in); //System.in 表示键盘输入
        try{
            i = sc.nextInt();
            System.out.printf("i = %d\n",i);
        }catch(InputMismatchException e){
            System.out.printf("输入的数据不合法,程序被终止!\n");
        }
    }
}

键盘输入int ,如果不是报错,抛出异常,可以在控制台上显示出错路径

public void f() throws IOException{
    throw new IOException(); //throw 抛出异常
}

throws 交给被掉出者执行,例如交给main函数处理

try{}
catch(exception){}
catch(){}
catch(){}
finally{}

无论有没有捕获到,finally最终都被执行(初始化上面的状态)

void f() throws A{
    .....
    .....
}

6.String类

6.1.String类

对字符串的处理

java.lang.String 类对象表示不可修改的Unicode 编码字符串

Unicode码,前面的是ASCII码表示的,而且范围很大,内存高

valueOf(int i)  //把String 转成 int 类型对象
class demo_2{
	public static void main(String[] args){
		String a = "123";
		int b = Integer.parseInt(a);
	}
}
//把String 转换成 int 类型
public class Test{
    public static void main(String[] args){
        String s1 = "sun java",s2 = "sun Java";
        System.out.println(s1.charAt(1)); //u
        System.out.println(s2.length());  //8
        System.out.println(s1.indexOf("java")); //4
        System.out.println(s1.indexOf("Java")); //-1
        System.out.println(s1.equals(s2)); //false
        System.out.println(s1.equalsIgnoreCase(s2));
        //true
        String s = "我是程序员,我在学java";
        String sr = s.replace('我','你');
        System.out.println(sr);
        //你是程序员,你在学Java
    }
}
public class test{
    public static void main(String[] args){
        int j = 1234567;
        String sNumber = String.valueOf(j);
        System.out.println("j 是"+sNumber.length()+"位数。");
        String s = "Mary,F,1976";
        String[] sPlit = s.split(",");
        for (int i=0; i<split.length; i++){
            System.out.println(sPlit[i]);
        }
    }
}

输出结果:

j 是7位数。

Mary

F

1976

6.2.StringBuffer类

String类本身没有改变字符串本身的方法,StringBuffer的作用正是如此;

delete方法,

public class TestStringBuffer{
    public static void main(String[] args){
        StringBuffer sb = new StringBuffer();
        sb.append("abc");
        sb.append("123");
        System.out.println("sb="+sb); //sb=abc123
        sb.insert(3,"__");
        System.out.println("sb="+sb); //sb=abc__123
        sb.delete(2,6); //把下标从2开始到6-1结束的字符删除
        System.out.println("sb=" + sb); //sb=ab23
        sb.reverse();
        System.out.println("sb="+sb);//sb = 32ba
        String str = sb.toString();
        System.out.printf("str="+str);//str=32ba
    }
}

6.3.ToString方法

证明class A中有toString方法【返回该对象的字符串表示】

class A{}
class demo_1{
	public static void main(String[] args){
	   A aa = new A();
	   System.out.printf("%s\n", aa.toString());
	}
}
//输出结果A@15db9742

A表示的是对象,@后面表示的是对象的地址的16进制的表示

class A{
	int x;
	int y;
    public A(int x, int y){
        this.x = x;
        this.y = y;
    }
    public String toString(){
        return "[" + x + "," + y + "]";
    }
}
class demo_1{
	public static void main(String[] args){
	   A aa = new A(1, 2);
	   System.out.printf("%s\n", aa.toString());
	    System.out.printf("%s", aa);
	}
}

重写toString 方法很有必要,返回类的信息

总结:

1.所有类都继承Object 类

2.Object 类中的toString 方法返回的是类的名字和该对象哈希码组成的一个字符串

3.System.out.println(类对象名);

4.为了实际需要,一般重写toString 方法

6.4.equals方法

缓冲:在传输的过程中建立缓冲,把数据打包,一次性发过来

String equal() 方法

class A{
	int x;
	int y;
    public A(int x, int y){
        this.x = x;
        this.y = y;
    }
    public boolean equals(Object obj){
       A aa = (A)obj;   //将aa
       if(this.x == aa.x)
       	return  true;
       else 
       	return false;
    }
}
class demo_1{
	public static void main(String[] args){
	   A aa1 = new A(1, 2);
	   A aa2 = new A(1, 2);
	   System.out.println(aa1.equals(aa2));
	}
}
//输出结果:true

总结:Object中的equals 方法是直接判断this 和 obj 本生的值是否相等,即用来判断调用equals 的对象和形参obj所引用的对象是否是同一对象,所谓同一对象就是指是内存中同一块存储单元,如果this 和obj 指向的是同一块内存对象,则返回true ,如果不是同一块内存,则返回false ,注意:即使是内容完全相等的两块不同的内存对象,则会返回false

equals 测试

class demo_2{
	public static void main(String[] args){
		String aa1 = new String("china");
		String aa2 = new String("china");
		System.out.println(aa1.equals(aa2));//aa1的equals方法调用aa2进行比较

             if(aa1 == aa2)
             System.out.println("aa1 == aa2");
             else
             System.out.println("aa1 == aa2");
             
             String aa3 = "china";
             String aa4 = "china";
             if(aa3 == aa4)
             System.out.println("aa3 == aa4");
             else
             System.out.println("aa3 == aa4");
	}
}

equals判断的是对象的指向是否相等;如果是判断自身的话用 == , if(aa1 == aa2);

new出来的在栈中存放,str3在另一个数据区存放

7.数组

数组可以存储一个类型的数据,比如可以存储 int 类型;

int[] arr1;
arr1 = new int[3];
int[] arr1 = new int[3];
int[] arr1 = new int[]{1,2,3};
int[] arr1 = {1,2,3};

数组的输出

showArr(arr1);

8.包

package demo.lin;

javac -d. 文件

package demo;
class A{
    void pront(){
        System.out.printf("hello");
    }
}
package demo;
class B{
    public static void main(String[] args){
        A aa = new A();
        aa.pront();
    }
}

import关键字的用法

导入包或者其他包中的类

import lib.lin.*;  //导入包
import lib.lin.demo;  //导入类

只有公有类的公有成员才能被访问

如何打包成夹包.jar

1.把要打包的文件放到一个空文件夹

2.cmd中输入 jar -cvf 生成的文件名.jar *

如何使用.jar包中的类

1.设置path路径 .jar文件地址+文件名.jar

jar文件的作用

1.发布和使用类库

2.便于资源的组合和管理

9.线程

四个问题:1.什么时进程 2.为什么需要进程 3.什么是线程 4.为什么需要线程

什么叫程序

严格有序的指令集合。程序规定了完成某项任务时,计算机所需做的各种操作。

单道程序设计环境:计算机中除了操作系统之外,只存在一个用户程序,即用户程序独享整个计算机资源;单道程序特点:

1.资源独占性:任何时候,位于内存中的程序可以使用一切资源

2.执行顺序性

3.结果的再现性

多道系统:

1.间断性

2.失去封闭性

3.不可再现性

进程:一个程序加载后的一次运行

class A extends Thread{
	public void run(){
		while(true){
			System.out.println("BBBB");
		}
	}
}
class demo_3{
	public static void main(String[] args){
		A aa = new A();
		aa.start();  //aa.start(); 会自动调run方法
		while(true){
			System.out.println("AAAA");
		}
	}
}
//第11行和第12行交替执行

前提: aa.start 和继承了 Thread类的类,Thread 里的 run 方法被重写;

创建进程的第一种方法:

1.创建一个继承类Thread 的子类

2.重写Thread类的run()方法

3.创建该子类的对象,通过该对象调用start()方法

注意:1.直接调用run方法是不会创建一个新的进程 2.执行一个线程就是执行run里的代码 3.执行完aa.start();后并不表示会立即执行该线程,只是获得了CPU执行的资格,但由于抢占cpu的线程很多,cpu并不一定立即去执行

启动一个线程必须用start()方法

三个状态:就绪、执行、阻塞

第二种方法

class A implements Runnable{
	public void run(){
		while(true){
			System.out.println("BBBB");
		}
	}
}
class demo_3{
	public static void main(String[] args){
		A aa = new A();
		Thread t = new Thread(aa);
		t.start();
		while(true){
			System.out.println("AAAA");
		}
	}
}

第二种方法:

1.定义一个实现了Runnable 接口的类

2.实现run方法

3.创建该类的对象

4.调用start方法

两种创建多线程方式的对比:

开发中优先选择实现Runnable接口的方式

原因:1.实现方式没有类单继承的局限性

​ 2.实现方式更适合来处理多个线程共享数据的情况

线程的优先级

MAX_PRIORITY:10

MIN_PRIORITY:1

NORM_PRIORITY:5 ——》默认优先级

2.如何获取和设置当前线程的优先级:

getPriority():获取线程的优先级

setPriority(int p):设置线程的优先级

线程通信

wait() notify() notifyAll() :此三个方法定义在Object类中

守护线程和主线程

线程的生命周期

Thread.State类中定义了线程的几种状态:

卖票过程中出现重票

当某个线程操作票数时没有操作完成,另一个线程进来,然后线程在结束后开始执行,出现0票

解决:当一个线程在操作共享数据时,其他线程不能参与进来,直到该线程结束,其他线程才能执行,即使该线程在阻塞状态

在Java中,通过同步机制,解决线程的安全问题

方式一:同步代码块

synchronized(同步监视器){

//需要被同步的代码

}

//说明:操作共享数据的代码,即为需要被同步的代码

​ 多个线程共同操作的变量是共享数据

​ 同步监视器,俗称:锁。任何一个类的对象,都可以充当锁

同步监视器:this Windos.class

方式二:同步方法

  1. 同步方法任然涉及到同步监视器,只是不需要我们显式声明
  2. 非静态的同步方法,同步监视器是:this
  3. 静态的同步方法,同步监视器是:当前类本身

死锁问题

介绍:不同的线程分别占用对方需要的同步资源不放,都在等待对方放弃自己需要的同步资源,就形成了死锁

不会出现异常和提示,只是所有线程都处于阻塞状态

解决办法:尽量不要嵌套,用算法解决,少用共同资源

Lock(锁)

JDK5.0开始,Java提供了更强大的线程同步机制

java.util.concurrent.locks.Lock接口是控制多个线程对共享资源进行访问的工具,锁提供了对共享资源的独占访问,每次只能有一个线程对Lock对象加锁,线程开始访问共同资源,需要先获得锁

面试题:synchronized和Lock的异同

同:都可以解决线程安全问题

不同:Lock需要手动锁(lock)和解锁(unlock),synchronized代码执行完后自动解锁

面试题:如何解决线程安全问题,有几个

Callable接口创建线程

callable实现线程比Runnable接口强大;

  1. call()可以返回值
  2. call()可以抛出异常,被外面的操作捕获,获取异常的信息
  3. Callable支持泛型

使用线程池

好处:

  1. 提高响应速度,减少创建线程的时间

  2. 降低资源消耗,重复使用线程池中线程,不需要每次都创建

  3. 便于线程管理

    corePoolSize:核心池的大小

    maxinumPoolSize:最大线程数

    keepAliveTime:线程没任务时最多保持多长时间后会终止

三个

sleep和wait的区别

sleep不会主动的释放锁,wait会主动释放锁

创建线程的四种方式

继承Thread类、实现Runnable接口、实现Callable接口、线程池(响应速度提高了,提高了资源利用率,便于管理)

10.AWT

10.1.GUI

  1. 组件
  2. 容器
  3. 事件

组件:文本框、按钮、

容器:用来存放组件的控件,控制组件的位置

10.2.布局管理器

1.容器对其内部的包含组件的排列方式,包含组件的位置和大小,被称为容器的布局

2.Java提供布局管理器来管理布局,而不建议直接设置组件在容器中的位置。

3.每个容器都有一个默认的布局管理器,当容器需要对某个组件进行定位或判断其大小尺寸时,就会自动调用其对应的布局管理器

4.在AWT中,常见的布局管理器

Borderlayout FlowLayout GridLayout

10.3事件处理:

  1. 事件
  2. 事件源
  3. 事件监听器
  4. 事件处理方法

事件监听器用来监控组件发生的某个事件,比如单击事件;

事件源在事件发生后会被事件监听器调用

frame.add(bn);  //添加按钮组件
A aa = new A(); //创建
bn.addActionListener(new B());   //添加一个监听器函数
class B extends WindowAdapter{
    public void windowClosing(WindowEvent e){
        System.exit(-1);
    }
}

通过一个对象对事件进行处理

总结:

1.告诉事件源可以自动产生哪类事件

2.设计好可以处理此类事件的事件监听器

一旦完成了这两部操作,当用户对事件源进行操作时,事件源就会自动产生事件,事件源就会自动把产生的事件封装成一个事件对象,事件源就会把封装好的事件对象传递给事件监听器

事件监听器收到事件源发过来的事件时,事件监听器就会自动调用相应的事件处理方法来对该事件进行相应的处理

import java.awt.*;
class TestGUI{
	public static void main(String[] args){
		Frame f = new Frame();
		f.setSize(300,300);
		f.setLayout(new GridLayout(2,1));
		Panel p1 = new Panel();
		p1.setLayout(new BorderLayout());
		Panel p1_1 = new Panel();
		p1_1.setLayout(new GridLayout(2,1));
		Button bn1 = new Button("BUTTON1");
		Button bn2 = new Button("BUTTON2");
		Button bn3 = new Button("BUTTON3");
		Button bn4 = new Button("BUTTON4");
		p1.add(bn1,BorderLayout.WEST);
		p1_1.add(bn3);
		p1_1.add(bn4);
		p1.add(p1_1,BorderLayout.CENTER);
		p1.add(bn2,BorderLayout.EAST);

		Panel p2 = new Panel();
		p2.setLayout(new BorderLayout());
		Panel p2_2 = new Panel();
		p2_2.setLayout(new GridLayout(2,2));
		Button bn5 = new Button("BUTTON5");
		Button bn6 = new Button("BUTTON6");
		Button bn7 = new Button("BUTTON7");
		Button bn8 = new Button("BUTTON8");
		Button bn9 = new Button("BUTTON9");
		Button bn10 = new Button("BUTTON10");
		p2.add(bn5,BorderLayout.WEST);
		p2.add(bn6,BorderLayout.EAST);
		p2_2.add(bn7);
		p2_2.add(bn8);
		p2_2.add(bn9);
		p2_2.add(bn10);
		p2.add(p2_2);


		f.add(p1);
		f.add(p2);
		f.pack();
		f.setVisible(true);
	}
}

例子:文本框相加

import java.awt.*;
import java.awt.event.*;
public class TestTextField_1{
	public static TextField tf1, tf2, tf3;
	public static void main(String[] args){
		tf1 = new TextField(30);
		tf2 = new TextField(30);
		tf3 = new TextField(30);
		Button bn = new Button("=");
		Label Lb = new Label("+");
		Frame f = new Frame("add file");

		f.setLayout(new FlowLayout());
		f.add(tf1);
		f.add(Lb);
		f.add(tf2);
		f.add(bn);
		f.add(tf3);

		bn.addActionListener(new MyMonitor());
		f.pack();
		f.setVisible(true);

	}
}
class MyMonitor implements ActionListener{
	@Override
	public void actionPerformed(ActionEvent e){
		String str1 = TestTextField_1.tf1.getText();
		String str2 = TestTextField_1.tf2.getText();
		int num1 = Integer.parseInt(str1);
		int num2 = Integer.parseInt(str2);
		int num3 = num1 + num2;
		Integer it = new Integer(num3);
		String str3 = it.toString();
		TestTextField_1.tf3.setText(str3);
	}
}

例子:编出一个计算器

10.4 可运行Jar包的生成

  1. 新建一个记事本文件,假设为1.txt 文件内容:

    Main-Class:可运行类的名字

    附注:记得最后敲回车

  2. dos 下命令:

    jar cvfm haha.jar 1.txt *.class

    记住:只有GUI程序生成的class文件才可以作为main class

11.内部类

12.流

12.1 什么是流

​ :连接程序和文件的“管道”;读取、写入、修改文件

流的分类与使用:

  1. ​ 四大基本抽象流
  2. ​ 文件流
  3. ​ 缓冲流
  4. ​ 转换流
  5. ​ 数据流
  6. ​ print流
  7. ​ Object流

按流的方向不同可以分为输入流和输出流,

按处理数据单位不同可以分为字节流和字符流

按照功能的不同可以分为节点流和处理流

字节流 字符流
输入流 InputStream Reader
输出流 OutputStream Writer

节点流与处理流(原始流与包裹流)

12.2 四大基本流介绍

字节流 字符流
输入流 InputStream Reader
输出流 OutputStream Writer

12.2.1 FileInputStream流中的常用方法

public int read() throws IOException

​ 读取一个字节并以整数形式返回

​ 如果读取到输入流的末尾则返回 -1

public int read(byte[] b); throws IOException

  • ​ 从输入流中读取一定数量的字节,并将其存储在缓存区数组 b 中。以整数形式返回实际读取的字节数
  • 如果 b 的长度为 0 ,则不读取任何字节并返回 0 ;如果因为流位于文件末尾而没有可用的字节,则返回 -1;
  • 例子:
  • FileInputStream fis = new FileInputStream("d:\\share\\errorlog.txt");
  • len = fis.read(buf); //从fis流所关联的d:\\share\\errorlog.txt 文件中读取数据,并将读取出来的数据写入buf 数组中,返回值是实际写入buf 数组的字节个数,如过读取到文件的结尾,则返回 -1

12.2.2 FileOutputStream流中的常用方法

12.2.3 FileReader流的常用方法

12.2.4 FileWriter流中常用方法

12.3 文件流

import java.io.*;											//导入IO包
public class Java_io{
	public static void main(String[] args)throws Exception{	//抛出异常
		FileReader fr = new FileReader("E:/1.txt");			//定义读文件
		int ch;												//定义变量
		ch = fr.read();										//从fr中读取
		while(-1 != ch){									//判断是否读完
			System.out.printf("%c", (char)ch);				//以字符的形式输出到控制台
			ch = fr.read();									//再次读取
		}
		fr.close();											//关闭fr的读操作
	}
}
//该程序读取e盘下的1.txt文件

用字符流进行文件的Copy

import java.io.*;											//导入IO包
public class demo{
	public static void main(String[] args)throws Exception{	//抛出异常
		FileReader fr = new FileReader("E:/demo.java");		//定义读文件类
		FileWriter fw = new FileWriter("E:/zhangshan");		//定义写文件类
		int ch;												//定义字节变量
		ch = fr.read();										//从demo.java中读一个字节
		while(-1 != ch){									//判断是否到文件最后
			fw.write(ch);									//写入zhangshan文件
			ch = fr.read();									//再读取一个字节
		}
		fw.flush();  										//刷新
		fr.close();											//关闭读的文件;包含flush();
		fw.close();											//关闭写的文件
	}
}

用字节流进行视频的Copy

import java.io.*;														//导入java.IO包
public class demo{
	public static void main(String[] args)throws Exception{
		FileInputStream fr = new FileInputStream("E:/1.MP4");			//实化字节流的读类
		FileOutputStream fw = new FileOutputStream("E:/zhangshan.MP4");	//实化字节流的写类
		int ch;															//定义变量
		ch = fr.read();													//从fr对象中读取
		while(-1 != ch){												//判断是否到文件结尾
			fw.write(ch);												//写到fW对象中
			ch = fr.read();												//再次读取
		}
		fw.flush();														//刷新
		fw.close();														//关闭写文件
		fr.close();														//关闭读文件
	}
}

FileInputStream的使用

12.4 缓冲流

  • 缓冲流就是带有缓冲区的输入输出流
  • 缓冲流可以显著的减少我们对IO访问的次数,保护我们的硬盘
  • 缓冲流本身就是处理流(处理流也叫包裹流),缓冲流必须得依附于节点流(节点流也叫原始流)
  • 处理流是包裹在原始节点流上的流,相当于包裹在管道上的管道

import java.io.*;												//导入IO包
public class demo{
	public static void main(String[] args)throws Exception{		//抛异常
		BufferedInputStream bis = new BufferedInputStream(new
FileInputStream("E:/1.MP4"));									//在输入流外包裹缓冲流
		BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("E:/zhangshan.MP4"));							//在输出流外包裹缓冲流
		byte [] buf = new byte[1024];							//定义字节数组(缓冲大小)
		int len;												//定义变量
		len = bis.read(buf);									//读取到len变量中
		while(-1 != len){										//判断是否读完
			bos.write(buf, 0, len);								//写入bos类
			len = bis.read(buf);								//再次读取
		}
		bos.flush();
		bos.close();
		bis.close();
	}
}

12.5 数据流



​ 下面是数据流的用法,其中第七行new 出来的ByteArrayOutputStream类自动带有一个Byte类型的数组;但是由于没有办法输入到数组中的方法,所以在外面又包裹了一层DataOutputStream数据流,其中DataOutputStream中有readLong方法,可以把程序中的long变量输入ByteArrayOutputStream进去。

12.6 转换流

import java.io.*;
public class demo{
	public static void main(String[] args)throws Exception{
		String str = null;
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		str = br.readLine();
		System.out.println("str =" + str);
	}
}

解析:第五行的BufferedReader必须接收的是Write流,所以利用InputStreamReader将System.in转化成Write流

Print流

只有输出,没有输入

分类:PrintWriter 输出字符 PrintStream 输出字节

13. 容器

import java.util.*;
public static void main(String[] args){
    ArrayList a1 = new ArrayList();
    a1.add(12345);			//自动装成Integer对象
    a1.add("张三");
    a1.add(66.66);
    a1.add(new A());
    System.out.println(a1);
}

Collections类

import java.util.*;
public class demo2{
	public static void main(String[] args){
		List It = new LinkedList();
		for(int i=0; i<7; ++i){
			It.add("a" + i);
		}
		System.out.println(It);
		Collections.shuffle(It);
		System.out.println(It);
		Collections.sort(It);
		System.out.println(It);
		Collections.reverse(It);
		System.out.println(It);
		System.out.println(Collections.binarySearch(It,"a5"));
		Collections.sort(It);
		System.out.println("重新排序之后:" + It);
		System.out.println(Collections.binarySearch(It,"a5"));
	}
}

14.常用类

String

string类的两种创建方法:

String s1 = "s1"; s1在栈中,"s1"在字符串常量池中

同样的变量,是两个栈区的指针指向方法区的同一个变量,只要对其中一个值操作就会重新开辟一块内存

String s2 = new String("s2"); s2在栈中,指向堆中的value地址,然后堆中的value指向字符串常量池中的数据地址

字符串常量池:不存储相同的数据,所以两个变量值相同,最终指向的都是同一块内存,new出来的变量在堆中会有个中间指针

String s1 = "SEE";
String s2 = new String("SEE");
System.out.println(s1 == s2); 	//false

结论:

  1. 常量与常量的拼接结果在常量池中,且常量池中不会存在相同内容的常量
  2. 只要其中有一个是变量,结果就在堆中
  3. 如果拼接的结果调用intern()方法,返回值就在常量池中

类型转化

String --> 基本数据类型,包装类:调用包装类的静态方法:Integer.parseXxx(str)

基本数据类型、包装类 --> String:调用String重载的valueOf(XXX)

String和char转化

String --> char():调用String的toStringArray()

char[] --> String:调用String的构造器

char[] charArray = str1.toCharArray();

String和byte[ ]转化

String --> byte[ ]:调用String的getBytes("utf-8"); 使用utf-8转成字节码还有(gbk)

byte[ ] --> String:调用string的构造器

posted @ 2020-10-24 09:26  MAOCE  阅读(89)  评论(0)    收藏  举报