Java进阶(泛型、文件管理与I/O流、多线程编程)

Java泛型
定义:泛型方法在调用时可以接收不同类型的参数,根据参数类型编译器适当地处理每一个方法调用。
作用:泛型可以最大限度重用代码,保护类型的安全以及提高性能。

Java泛型使用
泛型三种使用方式:泛型类、泛型接口、泛型方法
1、泛型类型用于类的定义中,被称为泛型类。通过泛型可以完成对一组类的操作对外开放相同的接口。最典型的就是各种容器类,如:List、Set、Map。泛型类,是在实例化类的时候指明泛型的具体类型;
2、泛型接口与泛型类的定义及使用基本相同。
3、泛型方法,是在调用方法的时候指明泛型的具体类型 。

下文转载至:https://blog.csdn.net/u013421629/article/details/82260547
参考《Java从小白到大牛》关东升 著
文件管理File类
一、简单介绍
1、程序经常需要访问文件和目录,读取文件信息或写入信息到文件,在 Java 语言中对文件的读写是通过 I/O 流技术实现的。
2、Java 语言使用 File 类对文件和目录进行操作,查找文件时需要实现 FilenameFilter 或FileFilter 接口。另外,读写文件内容可以通过 FileInputStream、FileOutputStream、FileReader和 FileWriter 类实现,它们属于 I/O 流。这些类和接口全部来源于 java.io 包。
3、File 类表示一个与平台无关的文件或目录。File 类名很有欺骗性,初学者会误认为是File 对象只是一个文件,但它也可能是一个目录。
二、File常用方法
1、构造方法
File(String path):如果 path 是实际存在的路径,则该 File 对象表示的是目录;如 果 path 是文件名,则该File 对象表示的是文件。
File(String path, String name):path 是路径名,name 是文件名。
File(File dir, String name):dir 是路径对象,name 是文件名。
2、获得文件名
String getName( ):获得文件的名称,不包括路径。
String getPath( ):获得文件的路径。
String getAbsolutePath( ):获得文件的绝对路径。
String getParent( ):获得文件的上一级目录名。
3、文件属性测试
boolean exists( ):测试当前 File 对象所表示的文件是否存在。
boolean canWrite( ):测试当前文件是否可写。
boolean canRead( ):测试当前文件是否可读。
boolean isFile( ):测试当前文件是否是文件。
boolean isDirectory( ):测试当前文件是否是目录。
4、文件操作
long lastModified( ):获得文件最近一次修改的时间。
long length( ):获得文件的长度,以字节为单位。
boolean delete( ):删除当前文件。成功返回 true,否则返回 false。
boolean renameTo(File dest):将重新命名当前 File 对象所表示的文件。成功返回true,否则返回
false。
5、目录操作
boolean mkdir( ):创建当前 File 对象指定的目录。
String[] list():返回当前目录下的文件和目录,返回值是字符串数组。
String[] list(FilenameFilter filter):返回当前目录下满足指定过滤器的文件和目录,参数是实现 FilenameFilter 接口对象,返回值是字符串数组。
File[] listFiles():返回当前目录下的文件和目录,返回值是 File 数组。
File[] listFiles(FilenameFilter filter):返回当前目录下满足指定过滤器的文件和目录,参数是实现 FilenameFilter 接口对象,返回值是 File 数组。
File[] listFiles(FileFilter filter):返回当前目录下满足指定过滤器的文件和目录,参数是实现 FileFilter 接口对象,返回值是 File 数组。
6、过滤器接口
对目录操作有两个过滤器接口:FilenameFilter 和 FileFilter。它们都只有一个抽象方法accept,
(1)FilenameFilter 接口中的 accept 方法如下:
boolean accept(File dir, String name):测试指定 dir 目录中是否包含文件名为 name 的文件。
(2)FileFilter 接口中的 accept 方法如下:
boolean accept(File pathname):测试指定路径名是否应该包含在某个路径名列表中。

文件过滤案例:
从指定目录(F:\PDF电子书籍\列出文件信息)中列出文件信息
在这里插入图片描述

import java.io.File;
import java.io.FilenameFilter;


public class FileOperator {
    public static void main(String[] args) {
//        用File对象表示一个目录,.表示当前目录
        File dir=new File("F:\\PDF电子书籍\\");     //指定目录地址,可修改

        Filter filter=new Filter("pdf");       //创建pdf文件过滤器,格式可修改
        System.out.println("PDF文件目录:" + dir);

        // 列出目录F:\PDF电子书籍\下,文件后缀名为PDF的所有文件
        String files[] = dir.list(filter);

        // 遍历文件列表
        for (String fileName : files) {
        // 为目录F:\PDF电子书籍\下的文件或目录创建File对象
            File f = new File(dir, fileName);
        // 如果该f对象是文件,则打印文件名
            if (f.isFile()) {
                System.out.println("文件名:" + f.getName());
                System.out.println("文件绝对路径:" + f.getAbsolutePath());
                System.out.println("文件路径:" + f.getPath());
            } else {
                System.out.println("子目录:" + f);
            }
        }
    }

}



// 自定义基于文件扩展名的文件过滤器
class Filter implements FilenameFilter {
    // 文件扩展名
    String extent;
    // 构造方法
    Filter(String extent) {
        this.extent = extent;
    }
//    @Override
    public boolean accept(File dir, String name) {
// 测试文件扩展名是否为extent所指定的
        return name.endsWith("." + extent);
    }
}

死磕Java基础–Java中的I/O流,看这个就够了!
转载至:https://blog.csdn.net/sinat_33921105/article/details/81081452

多线程编程相关概念
线程安全: 多线程访问类时,无论线程通过何种调度方式,并且在主调代码中不需要任何额外的同步或者协同,这个类都能表现出正确的行为。
进程与线程: 进程是拥有资源的基本单位,线程是调度的基本单位。同一进程的中线程的切换不会引起进程的切换,不同进程中进行线程切换会引起进程的切换。

volatile的理解
1、Volatile 保证了共享变量的**“可见性”,指当一个线程的某个共享变量发生改变时,另一个线程能够读取到这个修改的值。
2、Volatile 可以禁止
重排序**。指令重排序是编译器和处理器为了高效对程序进行优化的手段,它只能保证程序执行的结果是正确的,但是无法保证程序的操作顺序与代码顺序一致。(尽可能减少寄存器的读取、存储次数,充分复用寄存器的存储值)
3、Volatile 能保持单个简单volatile变量的读/写操作的具有原子性。但不能保证自增自减的原子性。原子性,就是某系列操作步骤要么全部执行,要么都不执行。

为了实现volatile内存语义,JMM限制了对volatile重排序做了限制:
当第二个操作是volatile写时,不管第一个操作是什么,都不能重排序。
当第一个操作是volatile读时,不管第二个操作是什么,都不能重排序。
当第一个操作是volatile写,第二个操作是volatile读时,不重排序。

Java内存模型
定义:Java内存模型控制线程之间的通信,决定了一个线程对共享变量的写入何时对另一个线程可见。JMM的核心目标是提供足够强的内存可见性保证(happens-before规则)和放松对编译器和处理器的限制(禁止重排序)。

避免死锁的常见方法
(1)避免一个线程同时获取多个锁。
(2)避免一个线程在锁内同时占用多个资源,尽量保证每个锁只占用一个资源.
(3)尝试使用定时锁,使用lock.tryLock(timeout)来替代使用内部锁机制。
(4)对数据库锁,加锁和解锁必须在一个数据库连接里,否则会出现解锁失败的情况。

产生死锁的四个必要条件
1、互斥条件:一个资源每次只能被一个进程使用。
2、请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。
3、不剥夺条件:进程已获得的资源,在末使用完之前,不能强行剥夺。
4、循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。

死锁的解决方法
撤消陷于死锁的全部进程;
逐个撤消陷于死锁的进程,直到死锁不存在;
从陷于死锁的进程中逐个强迫放弃所占用的资源,直至死锁消失。
从另外一些进程那里强行剥夺足够数量的资源分配给死锁进程,以解除死锁状态

线程的几种可用状态
1、新建( new ): 新创建了一个线程对象。
2、可运行( runnable ): 线程对象创建后,其他线程(比如 main 线程)调用了该对象 的 start ()方法。该状态的线程位于可运行线程池中,等待被线程调度选中,获 取 cpu 的使用权 。
3、 运行( running ): 可运行状态( runnable )的线程获得了 cpu 时间片( timeslice ) ,执行程序代码。
4、阻塞( block ): 阻塞状态是指线程因为某种原因放弃了 cpu 使用权,也即让出了 cpu timeslice ,暂时停止运行。直到线程进入可运行( runnable )状态,才有 机会再次获得 cpu timeslice 转到运行( running )状态。阻塞的情况分三种:
(一). 等待阻塞:运行( running )的线程执行 o . wait ()方法, JVM 会把该线程放 入等待队列( waitting queue )中。
(二). 同步阻塞:运行( running )的线程在获取对象的同步锁时,若该同步锁 被别的线程占用,则 JVM 会把该线程放入锁池( lock pool )中。
(三). 其他阻塞: 运行( running )的线程执行 Thread . sleep ( long ms )或 t . join ()方法,或者发出了 I / O 请求时, JVM 会把该线程置为阻塞状态。 当 sleep ()状态超时、 join ()等待线程终止或者超时、或者 I / O 处理完毕时,线程重新转入可运行( runnable )状态。
5、死亡( dead ): 线程 run ()、 main () 方法执行结束,或者因异常退出了 run ()方法,则该线程结束生命周期。死亡的线程不可再次复生。
在这里插入图片描述

实现多线程的3种方法
转载至:Marvellous丶——Java多线程(创建线程的三种方式、线程与进程)
本文链接:https://blog.csdn.net/baolingye/article/details/90755640
1、继承Tread类,重写run函数(常用)
一、创建步骤
(一)自定义线程类继承Thread类
(二)重写run()方法,编写线程执行体
(三)创建线程对象,调用start()方法启动线程
二、案例

public class TestThread extends Thread{
    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            System.out.println(Thread.currentThread().getName()+"  "+ i);
        }
    }

    public static void main(String[] args) {
        new TestThread().start();
        new TestThread().start();
    }
}

2、实现Runnable接口(常用)
一、创建步骤
(一)定义Runnable接口实现类
(二)重写run()方法,编写线程执行
(三)创建线程对象,调用start()方法启动线程
二、案例

public class TestRunnable implements Runnable {

    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            System.out.println(Thread.currentThread().getName()+"  "+ i);
        }
    }

    public static void main(String[] args) {
        TestRunnable runnable = new TestRunnable();
        new Thread(runnable).start();
        new Thread(runnable).start();
    }
}

3、实现Callable接口
一、创建步骤
(一)实现Callable接口,需要返回值类型
(二)重写call方法,需要抛出异常
(三)创建目标对象
(四)创建执行服务:ExecutorService ser = Executors.newFixedThreadPool(1);
(五)提交执行:Future result1 = ser.submit(t1);
(六)获取结果:boolean r1 = result1.get()
(七)关闭服务:ser.shutdownNow()
二、特点
(一)call()方法可以有返回值
(二)call()方法可以声明抛出异常
三、案例

import java.util.concurrent.*;

public class TestCallable implements Callable<Boolean> {

    @Override
    public Boolean call() throws Exception {
        for (int i = 0; i < 10; i++) {
            System.out.println(Thread.currentThread().getName()+"  "+ i);
        }
        return true;
    }

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        TestCallable testCallable = new TestCallable();

        //创建执行服务
        ExecutorService service = Executors.newFixedThreadPool(2);

        //提交执行
        Future<Boolean> submit = service.submit(testCallable);
        Future<Boolean> submit1 = service.submit(testCallable);

        //获取结果
        Boolean aBoolean = submit.get();
        Boolean aBoolean1 = submit1.get();

        //判断线程是否顺利结束或者有异常
        System.out.println(aBoolean);
        System.out.println(aBoolean1);

        //关闭服务
        service.shutdownNow();
    }
}

线程的三种方式对比
1、采用实现Runnable,Callable接口的方式创建多线程,还可以继承其他类,多个线程可以继承共享同一个目标对象,所以非常适合多个相同线程来处理同一份资源的情况
2、采用继承Thread类的方式创建多线程,不能再继承其他父类

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值