java和java基础2

向下转型

有了对象的多态性后,内存中实际上是加载了子类特有的属性和方法,但是由于变量声明为父类型,导致编译时,只能调用父类中声明的属性和方法,子类的特有属性和方法不能调用,要是用则需要使用向下转型:

Person person = new Man();  
Man man = (Man)person;  

关键字 instanceof

a instanceof A : 判断对象a 是否是类A的实例
为了避免向下转型出现异常,可先用instanceof来进行判断

@Test
public void testStudent() {
    Persion persion = new Student();

    if(persion instanceof Student) {
        Student student = (Student)persion;
        student.eat();
    }
}

Object类的使用

方法: finalize : 在垃圾回收之前会调用此方法,一般系统会自动进行调用无需手动进行操作

Object equals方法

== 和equals的区别:

== 是运算符, equals是方法  

== 使用在 基本数据类型 和 引用数据类型  
如果是引用类型的比较,则 == 比较的是两个地址值是否相等  

equals : 判断两个对象是否相等

equals,是方法,所以他只能适用于引用数据类型   
String, Date, File, 包装类等 都重写了Object的Equals方法  

关键字 toString()

toString();方法源码:getClass().getName() + "@" + Integer.toHexString(hashCode());
String,Date,File,包装类等都重写了Object类中的toString()方法

包装类Wapper

让基本数据类型也具有类的特征

基本数据类型    包装类  
byte            Byte  
short           Short  
int             Integer  
long            Long  
float           Float  
double          Dounble  
boolean         Boolean  
char            Character 

基本数据类型和包装类的转换

基本数据类型转包装类
int num1 = 20;
Integer num2 = new Integer(num1);
System.out.println(num2.toString());

Integer int1 = new Integer("123");
System.out.println(int1.toString());

包装类 转 基本数据类型 xxxValue  
Integer num3 = new Integer("12345");
num3.intValue();

自动装箱

int aa = 10;
Integer int1 = aa;  //自动装箱 

int bb = int1;  //自动拆箱

自动拆箱 数字转字符串  
方法一: 
String str1 = bb + "";
方法二:  
string.valueof(bb); 

字符串转数字
Integer.parseInt("54321")

关键字 static

static:静态变量,多个对象共享同一个静态变量,当通过某个对象修改静态变量,也会导致其他对象调用此静态变量时,也是修改过了

静态方法:只能调用静态方法或属性; 非晶态方法既可以调用非晶态的方法和属性也可以调用静态方法和属性

静态方法不可调用this, super

什么时候使用static?
1、属性可以被多个对象共享的,不会随着对象的不同而不同
2、工具类的方法,习惯上声明为static
3、操作静态属性的通常使用静态方法

单利模式

package cn.onbe.entry;

public class Bank {

    private static Bank instances = null;

    // 1、私有化类的构造器
    private Bank() {

    }

    // 提供公共方法,返回类的对象
    public static Bank getInstance() {

        if (instances == null) {
            instances = new Bank();
        }

        return instances;
    }
}

代码块

代码块只是一个大括号:{}
作用:初始化类,对象,只能使用static进行修饰,分作静态代码块和非静态代码块
静态代码块:随着类的加载而执行,只执行一次,初始化信息
非静态代码块:随着对象的创建而执行,每创建一个对象执行一次,可以在创建对象时,对对象进行初始化

关键字final

finall : 可修饰如下: 类:不可进行继承
方法: 不可再被重写
变量: 修饰变量,则此时称为一个常量
出现位置:显示初始化,代码块,构造器中的初始化

final修饰局部变量,尤其是修饰型参,表明型参是一个常量,
final static : 修饰属性,通常称为全局常量

抽象类

抽象类:abstract ,表示不能再被实例化
抽象方法:没有方法体,子类必须要实现方法体 当一个类里面,一些方法是固定的则把固定的写出来,另外一些代码是可变的,则可以把这些抽象的方法进行抽象,形成抽象方法

模版方法设计模式

接口

interface : 接口不能定义构造器, 可定义如下属性:
全局常量: public static final
抽象方法: public abstract
实现接口: implements, 子类必须实现接口的全部抽象方法
java实现多个接口 ,弥补java单继承的极限

class AA exentds BB implements CC, DD, EE
jdk8的接口可以定义静态方法,默认方法
接口中的静态方法只能用接口来调用
实现类可以调用默认方法
默认方法:default
接口和接口可以实现继承

异常处理

Throwable  
    Error  
    Exception  
        编译时异常  
            IOException  
                FileNotFoundException  
            ClassNotFoundException
        运行时异常  
            NullPointerException
            ArrayIndexOutOfBoundsException
            ClassCastException //类型转换异常
            NumberFormatException
            InputMismatchException
            ArithmeticException

异常处理

try-catch-finally : 自己能处理,解决掉错误
throws+异常类型 : 自己不能解决,抛回上一级进行处理
抓抛模型: 程序在正常运行的过程中,一旦出现异常,就会在异常代码处生成一个对应异常类的对象,并将此对象抛出,一旦抛出对象后,其后面的代码就不再执行。
过程1:“抓” : 可以理解为异常的处理方式 , try-catch-finally throws
在try 定义中的变量,再出了try大括号之后,变量是不可用的,必须在try之前进行声明,才可进行调用
finally 一定会被执行的代码,catch 中有出现异常了,try有return语句,catch有return语,finally都会被执行
像数据库连接,输入输出流,网络编程Socket等资源,JVM是不能自动回收的,我们需要自己手动的进行志愿的释放

try {
    //  可能出现异常的代码
} catch(异常类型 变量名) {
    //异常处理方式
} finally {
    // 一定会执行的代码  
}

String str = "fsdsffs";
str = "abc";
try {
    int num = Integer.parseInt(str);
} catch (NumberFormatException e) {
    System.out.println(e.getMessage());
    // e.printStackTrace(); 
}

throws + 异常类型

throws抛出的异常之后,后面的代码就不再执行

怎么使用 :
如果开发中父类没有throws,则子类也不能用throws,只能用tru-catch  
执行的方法中先后又调用了另外的几个方法,这几个方法是递进关系执行的,建议这几个方法使用throws的方式进行处理,  

手动生成异常

public void regist(int id) throws Exception{
    if(id > 0) {
        System.out.println("输入正确");
    } else {
        throw new Exception("输入非法的参数");
    }
}

线程

程序: 完成特定任务,用某种语言编写的一组指令的集合
进程: 是程序的一次执行过程,或是正在运行的一个程序。是一个动态的过程,有它自身的产生,存在和消亡的过程。--生命周期
进程作为资源分配的单位,系统在运行时会为每个进程分配不同的内存区域
线程:进程可以进一步细化为线程,是一个程序内部的一条执行路径。

若一个进程同一时间并行执行多个线程,就是支持多个线程
线程作为调度和执行的单位,每一个线程拥有独立的运行栈和程序计数器,线程切换的开销小

并行和并发

并行: 多个cpu同时执行多个任务,比如多个人同时做不同的事。 并发: 一个cpu同时执行多个任务,比如:秒杀,多个人做同一件事情。

多线程的有点

何时需要多线程?
程序需要同时执行两个或多个任务。
程序需要实现一些需要等待的任务时,如用户输入,文件读写操作,网络操作,搜索等
需要一些后台运行的程序

Thread创建

1、创建一个继承于Thread的子类  
2、重写Thread的run方法  
3、创建Thread类的子类的对象  
4、通过此对象调用start
多线程  
package cn.emam;

public class ThreadTest extends Thread{

    @Override
    public void run() {
       for (int i = 0; i < 100; i++) {
           if (i %2 == 0) {
               System.out.println(i);
           }
       }
    }
}
主线程
public static void main(String[] args) {
    ThreadTest testThread = new ThreadTest();
    testThread.start();
}

线程的常用方法

start : 启动当前线程,调用当前线程的run()
run(): 通常需要重写Thread类中的此方法,
currentThread(): 静态方法,返回执行当前代码的线程  
getName(): 获取当前线程的名字  
setName():设置当前线程的名称  
yield(): 释放当前cpu执行权
join(): 在线程A中调用线程B的join方法,此时线程A就进入阻塞状态,直到线程B执行完后,线程A才结束阻塞状态
sleep(毫秒) :休眠
isAlive()  判断当前线程是否存活 
Thread.currentThread().getName()

线程优先级

MAX_PRIORITY:10
MIN_PRIORITY: 1
NORM_PRIORITY:5

涉及的方法:

getPriority()返回线程优先级
setPriority(int NewPriority): 改变线程的优先级

Runnable接口

创建一个实现了Runnable接口的类
实现类去实现run()
创建实现类的对象
将此对象作为参数传递到Thread类的构造器中,创建Thread类的对象
通过Thread类的对象调用start

public class RThread implements Runnable{
    static  final int MAX_COUNT = 100;

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

Thread thread = new Thread(new RThread());
thread.start();

Thread 和 Runnable的比较

开发中优选选择 Runnable 方式
原因:1、实现的方式没有类的单继承性的极限性
2、实现的方式更适合来处理多个线程共享数据的情况

线程的生命周期

新建 -> 就绪 -> 运行 -> 阻塞 -> 死亡
阻塞:sleep(), join(), wait(),等待同步锁

线程安全

线程安全: 当一个线程程序正在运行中,其他线程参与进来,也操作正在运行中的程序,这样导致线程安全
解决:
方式一:同步代码块, synchronized

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

说明:操作共享数据的代码,即为需要被同步的代码  
共享数据:多个线程共同操作的变量
同步监视器:就是锁,任何一个类的对象都可以充当锁,多个线程必须要共用同一把锁  

public class Rthread implements Runnable {
    private int ticket = 100;
    Object obj = new Object();

    @Override
    public void run() {
        while (true) {
            synchronized (this) {  // synchronized (obj) {  synchronized (Rthread.class) {
                if (ticket > 0) {
                    System.out.println(Thread.currentThread().getName()+ "剩余票=>" + ticket);
                    ticket--;
                }
            }
        }
    }
}

方式二 同步方法

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

@Override
public void run() {
    while (true) {
        sellTick();
    }
}

private synchronized void sellTick() {
    if (ticket > 0) {
        System.out.println(Thread.currentThread().getName()+"线程=》"+ticket);
        ticket--;
    }
}

单利模式可能存在线程安全需要进行锁处理

public class Bank {
    private static Bank instance = null;

    public Bank() { }
    public static synchronized Bank getInstance() {
        if (instance == null) {
            instance = new Bank();
        }
        return instance;
    }
}

死锁

死锁:不同的线程分别占用对方需要的同步资源不放弃,都在等待对方放弃自己需要的同步资源,就形成死锁
程序中应避免死锁

Lock

public class Sthread implements Runnable{
    private int ticket = 100;
    private ReentrantLock lock = new ReentrantLock();

    @Override
    public void run() {
        while (true) {
            try {
                lock.lock();

                if (ticket > 0) {
                    System.out.println(Thread.currentThread().getName()+"线程:=》"+ticket);
                    ticket--;
                }

            } finally {
                lock.unlock();
            }
        }
    }
}

线程问题优先使用顺序

Lock->同步代码块->同步方法

线程通讯

必须使用在同步代码块和同步方法中  

wait():一旦执行此方法,当前线程就进入阻塞状态,并释放同步监视器  

notify(): 一旦执行此方法,就会唤醒被wait的一个线程,如果有多个线程被wait,就唤醒优先级高的那个  

notify():唤醒所有wait的所有线程  

sleep和wait异同

线程池

提高相应时间 降低资源消耗
便于线程管理

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ThreadPool {
    public static void main(String[] args) {
        // 1、提供制定线程数量的线程池
        ExecutorService service = Executors.newFixedThreadPool(10);
        // 执行制定的线程操作。需要提供实现Runnable接口或者callable接口实现类的对象
        //适合适用于Runnable
        service.execute(new NumberThread());
        //service.submit(); // 适用于callable
        service.shutdown();
    }
}

class NumberThread implements Runnable {
    private static final int MAX_NUM = 100;

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