栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Java笔记

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Java笔记

1.递归方法 1.1定义:

递归方法:一个方法体内调用它自身。

1.2如何理解递归方法?

方法递归包含了一种隐式的循环,它会重复执行某段代码,但这种重复执行无须循环控制。

递归一定要向已知方向递归,否则这种递归就变成了无穷递归,类似于死循环。

1.3举例:
// 例1:计算1-n之间所有自然数的和
	public int getSum(int n) {// 3

		if (n == 1) {
			return 1;
		} else {
			return n + getSum(n - 1);
		}
	}

	// 例2:计算1-n之间所有自然数的乘积:n!
	public int getSum1(int n) {

		if (n == 1) {
			return 1;
		} else {
			return n * getSum1(n - 1);
		}

	}
	
	//例3:已知一个数列:f(0) = 1,f(1) = 4,f(n+2)=2*f(n+1) + f(n),
	//其中n是大于0的整数,求f(10)的值。
	public int f(int n){
		if(n == 0){
			return 1;
		}else if(n == 1){
			return 4;
		}else{
			return 2*f(n - 1) + f(n - 2);
		}
	}

    @Test
    public void testRecursion(){
    	//例1
        System.out.println(getSum(3)); //6
        //例2
        System.out.println(getSum1(3));	//6
        //例3
        System.out.println(f(10));	//10497
    }
    //例3笔记
    //f(10)= 2 * f(10-1) + f(10-2);//继续调用f()传进去10-1
    //f(9)= 2 * f(9-1) + f(9-2);//继续调用f()传进去9-1
    //~~~
	//f(1)  return 4
	//f(0)  return 1
	//f(3)  return 2 * 4 + 1;   //9
	//f(4)  return 2 * 9 + 4;	//22
	//~~~
	//例4:斐波那契数列
	
	//例5:汉诺塔问题
	
	//例6:快排

2.单例模式 2.1 饿汉模式
//饿汉模式1:
public class Blank {
    private Blank (){}
    private static Blank blank = new Blank ();
    private static Blank getInstance(Blank blank ){
        return blank ;
    }
}

//饿汉模式2:使用静态代码块
public class Blank {
    private Blank (){}
    private static Blank blank = null;
    static{
         blank = new Blank ();
    }
    private static Blank getInstance(){
        return blank ;
    }
}
2.2懒汉式
public class Order{
	private Order(){}
	private static Order order = null;
	public static Order getInstance(){
			if(order){
				order = new Order();
			}
			return order;
	}
}
6.4 两种方式的对比:

饿汉式:

  • 坏处:对象加载时间过长。
  • 好处:饿汉式是线程安全的

懒汉式:

  • 好处:延迟对象的创建。

  • 目前的写法坏处:线程不安全。—>使用多线程可以解决

3.代码块

1.代码块的作用:用来初始化类、对象的信息
2.分类:代码块要是使用修饰符,只能使用static

3.1静态代码块

内部可以输出语句
随着类的加载而执行,而且只执行一次
作用:初始化类的信息
如果一个类中定义了多个静态代码块,则按照声明的先后顺序执行
静态代码块的执行要优先于非静态代码块的执行
静态代码块内只能调用静态的属性、静态的方法,不能调用非静态的结构

3.2非静态代码块

内部可以输出语句
随着对象的创建而执行
每创建一个对象,就执行一次非静态代码块
作用:可以在创建对象时,对对象的属性等进行初始化
如果一个类中定义了多个非静态代码块,则按照声明的先后顺序执行
非静态代码块内可以调用静态的属性、静态的方法,或非静态的属性、非静态的方法

4.抽象类 4.1可以用来修饰:类、方法

abstract修饰类:抽象类

此类不能实例化

抽象类中一定有构造器,便于子类实例化时调用(涉及:子类对象实例化的全过程)

开发中,都会提供抽象类的子类,让子类对象实例化,完成相关的操作 —>抽象的使用前提:继承性

abstract修饰方法:抽象方法

抽象方法只方法的声明,没方法体

包含抽象方法的类,一定是一个抽象类。反之,抽象类中可以没有抽象方法的。

若子类重写了父类中的所有的抽象方法后,此子类方可实例化

若子类没重写父类中的所的抽象方法,则此子类也是一个抽象类,需要使用abstract修饰

4.2 注意点:

abstract不能用来修饰:属性、构造器等结构

abstract不能用来修饰私有方法、静态方法、final的方法、final的类

4.3 abstract应用的举例
abstract class GeometricObject{
public abstract double findArea();
}
class Circle extends GeometricObject{
private double radius;
public double findArea(){
		return 3.14 * radius * radius;
	};
}

举例二:IO流中设计到的抽象类:InputStream/OutputStream / Reader /Writer。在其内部
定义了抽象的read()、write()方法。
5. 多线程 5.1、程序(program)

概念:是为完成特定任务、用某种语言编写的一组指令的集合。即指一段静态的代码。

5.2、进程(process)

概念:程序的一次执行过程,或是正在运行的一个程序。

说明:进程作为资源分配的单位,系统在运行时会为每个进程分配不同的内存区域

5.3、线程(thread)

概念:进程可进一步细化为线程,是一个程序内部的一条执行路径。

说明:线程作为调度和执行的单位,每个线程拥独立的运行栈和程序计数器(pc),线程切换的开销小。

5.4、并行、并发

并行:多个CPU同时执行多个任务。比如:多个人同时做不同的事。

并发:一个CPU(采用时间片)同时执行多个任务。比如:秒杀、多个人做同一件事

5.5、多线程的创建

方式一:继承Thread类的方式:

  1. 创建一个继承于Thread类的子类
  2. 重写Thread类的run() --> 将此线程执行的操作声明在run()中
  3. 创建Thread类的子类的对象
  4. 通过此对象调用start():①启动当前线程 ② 调用当前线程的run()

说明两个问题:

问题一:我们启动一个线程,必须调用start(),不能调用run()的方式启动线程。
问题二:如果再启动一个线程,必须重新创建一个Thread子类的对象,调用此对象的start().

方式二:实现Runnable接口的方式:

  1. 创建一个实现了Runnable接口的类

  2. 实现类去实现Runnable中的抽象方法:run()

  3. 创建实现类的对象

  4. 将此对象作为参数传递到Thread类的构造器中,创建Thread类的对象

  5. 通过Thread类的对象调用start()

两种方式的对比:

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

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

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

  • 联系:public class Thread implements Runnable
  • 相同点:两种方式都需要重写run(),将线程要执行的逻辑声明在run()中。
    目前两种方式,要想启动线程,都是调用的Thread类中的start()。
5.6 Thread类中的常用的方法:
  1. start():启动当前线程;调用当前线程的run()
  2. run(): 通常需要重写Thread类中的此方法,将创建的线程要执行的操作声明在此方法中
  3. currentThread():静态方法,返回执行当前代码的线程
  4. getName():获取当前线程的名字
  5. setName():设置当前线程的名字
  6. yield():释放当前cpu的执行权
  7. join():在线程a中调用线程b的join(),此时线程a就进入阻塞状态,直到线程b完全执行完以后,线程a才结束阻塞状态。
  8. stop():已过时。当执行此方法时,强制结束当前线程。
  9. sleep(long millitime):让当前线程“睡眠”指定的millitime毫秒。在指定的millitime毫秒时间内,当前线程是阻塞状态。
  10. isAlive():判断当前线程是否存活
5.7 线程的优先级:

MAX_PRIORITY:10

MIN _PRIORITY:1

NORM_PRIORITY:5 -->默认优先级

5.8 如何获取和设置当前线程的优先级:
  • getPriority():获取线程的优先级

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

说明:高优先级的线程要抢占低优先级线程cpu的执行权。但是只是从概率上讲,高优先级的线程高概率的情况下被执行。并不意味着只当高优先级的线程执行完以后,低优先级的线程才执行。

线程通信:wait() / notify() / notifyAll() :此三个方法定义在Object类中的。

5.9 Thread的生命周期


说明:

1.生命周期关注两个概念:状态、相应的方法
2.关注:状态a–>状态b:哪些方法执行了(回调方法)
某个方法主动调用:状态a–>状态b
3.阻塞:临时状态,不可以作为最终状态
4.死亡:最终状态。

5.10现成的同步机制

例子:创建个窗口卖票,总票数为100张.使用实现Runnable接口的方式

  1. 问题:卖票过程中,出现了重票、错票 -->出现了线程的安全问题

  2. 问题出现的原因:当某个线程操作车票的过程中,尚未操作完成时,其他线程参与进来,也操作车票。

  3. 如何解决:当一个线程a在操作ticket的时候,其他线程不能参与进来。直到线程a操作完ticket时,其他线程才可以开始操作ticket。这种情况即使线程a出现了阻塞,也不能被改变。

Java解决方案:同步机制

  1. 在Java中,我们通过同步机制,来解决线程的安全问题。

方式一:同步代码块

synchronized(同步监视器){
      //需要被同步的代码

   }
  

方式二:同步方法
如果操作共享数据的代码完整的声明在一个方法中,我们不妨将此方法声明同步的。

关于同步方法的总结:

  1. 同步方法仍然涉及到同步监视器,只是不需要我们显式的声明。

  2. 非静态的同步方法,同步监视器是:this

  3. 静态的同步方法,同步监视器是:当前类本身

方式三:Lock锁 — JDK5.0新增

使用的优先顺序:

  • Lock —> 同步代码块(已经进入了方法体,分配了相应资源 ) —> 同步方法(在方法体之外)

利弊
同步的方式,解决了线程的安全问题。—好处
操作同步代码时,只能一个线程参与,其他线程等待。相当于是一个单线程的过程,效率低。

5.11 线程安全的单例模式(懒汉式):
class Blank{
	private Blank(){}
	private static Blank blank = null;
	public static Blank getInstance(){
				//方式一,效率更低
				synchronized(Blank.class){
				if(blank == null){
					blank = new Blank();
		}
		return blank;
		}
	}
}

class Blank{
	private Blank(){}
	private static Blank blank = null;
	public static Blank getInstance(){
				//方式二,效率更高
				if(blank == null){
					synchronized(Blank.class){
							if(blank == null){
									blank = new Blank();
					}
				}
			}
			return blank;
	}
}
5.12死锁问题
  1. 死锁的理解:

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

    1. 出现死锁后,不会出现异常,不会出现提示,只是所有的线程都处于阻塞状态,无法继续
    2. 我们使用同步时,要避免出现死锁。
  3. 举例:

public static void main(String[] args) {
    StringBuffer s1 = new StringBuffer();
    StringBuffer s2 = new StringBuffer();

    new Thread(){
        @Override
        public void run() {
            synchronized (s1){

                s1.append("a");
                s2.append("1");

                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                synchronized (s2){
                    s1.append("b");
                    s2.append("2");

                    System.out.println(s1);
                    System.out.println(s2);
                }
            }
        }
    }.start();

    new Thread(new Runnable() {
        @Override
        public void run() {
            synchronized (s2){
                
                s1.append("c");
                s2.append("3");
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                synchronized (s1){
                    s1.append("d");
                    s2.append("4");

                    System.out.println(s1);
                    System.out.println(s2);
                }
            }
        }
    }).start();
}
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/1007315.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号