入职必备技能(二)Java基础

目录

调试技能

  • 双击行号左侧区域:设置断点
  • F11:启动调试程序
  • F5: 跳转到方法内部
  • F6: 单步调试
  • F8: 跳转到下一处断点

一维数组

基本语法:int[] arr = new int[10];

//冒泡排序
package basic;

public class SortDemo {
    public static void main(String[] args) {
        int[] unsortArr = {34,53,12,32,56,17};
        System.out.println("排序前的数组元素为:");
        for(int num:unsortArr) {
            System.out.println(num);
        }
        //冒泡排序,定了n-1个位置,最后一个位置也是确定的
        for(int index = 0; index < unsortArr.length - 1; index++) {
            // 如果已经确定了 i 个元素,自然就不需要再和他们进行比较了
            for(int comp = 0; comp < unsortArr.length - index - 1; comp++) {
                if (unsortArr[comp + 1] < unsortArr[comp]) {
                    int temp = -1;
                    temp = unsortArr[comp + 1];
                    unsortArr[comp + 1] = unsortArr[comp];
                    unsortArr[comp] = temp;
                }
            }
        }
        System.out.println("排序后的数组元素为:");
        for(int num:unsortArr) {
            System.out.println(num);
        }
    }
}

二维数组

基本语法
创建一个三行三列的int类型的数组
int[][] arr = new int[3][3];
创建一个三行不定列数的float数组
float[][] arr = new float[3][];
arr[0] = new float[4];
arr[1] = new float[3];
arr[2] = new float[5];

多态

编译时多态 

设计时多态,一般表现形式为方法的重载

运行时多态

程序运行时动态决定调用哪个方法,必须满足继承关系,而且是父类引用指向子类对象

向上向下转型

package basic;

import natapp.liujinliang.Father;
import natapp.liujinliang.Mother;
import natapp.liujinliang.Parents;

public class Poly {
    public static void main(String[] args) {

        System.out.println("向上转型==========");
        Parents m = new Mother();
        Parents f = new Father();
        System.out.println("向下转型==========");
        Mother mom = (Mother) m;
        Father daddy = (Father) f;

        //向上转型:可以调用子类重写父类的方法以及父类派生的方法,无法调用子类特有的方法
        m.test();
        f.test();

        //抽象类的作用:不可以被实例化,这就避免了无用类的实现
        //抽象方法作用:提醒开发者需要实现父类的哪些方法
        mom.love();
        daddy.love();

        //向下转型:必须使用强制类型转换,可以调用子类特有的方法
        mom.shopping();
        daddy.drinking();
    }
}
package natapp.liujinliang;

public abstract class Parents {

    public abstract void love();

    public void test(){ }
}
package natapp.liujinliang;

public class Father extends Parents {

    @Override
    public void love() {
        System.out.println("父爱如山");
    }

    public void drinking() {
        System.out.println("男人爱喝酒");
    }

    public void test() {
        System.out.println("爸爸的测试类");
    }
}
package natapp.liujinliang;

public class Mother extends Parents {

    @Override
    public void love() {
        System.out.println("母爱如水");
    }

    public void shopping() {
        System.out.println("女人爱购物");
    }

    public void test() {
        System.out.println("妈妈的测试类");
    }
}

输入输出流(包括字符流和字节流)

流:一连串流动的字符,以先进先出的方式发送信息的通道。
输出流:程序向目标写数据。
输入流:程序从数据源读数据。
分隔符:Windows是”\”,Linux是”/”
字节流:处理的基本单位单位是单个字节,他通常用来处理二进制数据,比如图形图像。InputStream和OutputStream是其祖先
字符流:处理的基本单位是Unicode字符(大小2字节),通常用来处理文本数据。Reader和Writer是其祖先

package file;

import java.io.File;
import java.io.IOException;

public class FileDemo {
    public static void main(String[] args) throws IOException {

        // 演示实例1
        File file = new File("c:\\liujinliang");
        File chFile = new File(file, "io\\test\\score.txt");

        // 演示实例2
        File file2 = new File("c:\\liujinliang\\io\\test", "score.txt"); 

        // 创建File类的对象
        File file1 = new File("d:\\score.txt");

        // 判断是文件还是目录
        System.out.println(file1.isFile());
        System.out.println(file1.isDirectory());

        // 创建目录
        if(!file.exists()) {
            file.mkdir();
        }

        // 创建文件
        if(!file1.exists()) {
            file1.createNewFile();
        }

    }
}

线程

线程生命周期

这里写图片描述
需要注意的是,唤醒线程的方法notify() || notifyAll()是针对wait()方法的。

进程和线程的概念

进程是指可执行程序并存放在计算机存储器的一个指令序列,他是一个动态执行的过程。线程相当于子程序。

进程 | 线程的创建

1、创建一个Thread类,或者一个Thread子类的对象。
2、创建一个实现Runnable接口的类的对象。

Thread类

构造方法 说明
Thread() 创建一个线程对象
Thread(String name) 创建一个具有指定名称的线程对象
Thread(Runnable target) 创建一个基于Runnable接口实现类的线程对象
Thread(Runnable target, String name) 创建一个基于Runnable接口实现类并且具有指定名称的线程对象
方法 说明
public void run() 线程体方法,一般需要重写。
public void start() 启动线程的方法
public void sleep(long m) 线程休眠m毫秒的方法
public void join() 线程抢占资源的方法

Runnable接口

只有一个 run() 方法
Runnable是Java中用以实现线程的接口
任何实现线程功能的类都必须实现该接口

反射

基本概念

Java在需要使用到某个类时才会将.class文档载入,在JVM产生java.lang.Class实例代表该文档,.class文档反映了类基本信息,因而从 Class 取得类信息的方式就称为反射(Reflection)。


基本关系梳理:.class文档是在编译过后生成的;Class实例在运行时由JVM生成。


核心:运行时(因为Class实例在运行时创建)


区别:编译时(new关键词创建对象,因为要获取构造函数的信息,所以只能从.class文档查看,而.class文档是在编译时生成)


一言以蔽之:反射从Class获取信息,属运行时;new从.class获取信息,属编译时。然而Class是由.class生成的。


意义:降低耦合度,有很多时候,我们只有在运行时才知道调用那个函数。

使用Class.forName()

背景: 在某些应用中,无法事先知道开发人员要使用哪个类。例如,实现不知道开发人员会是用哪个厂商的的JDBC驱动程序,也就不知道厂商java.sql.Driver接口的类名称为什么,因而必须让开发人员可以事后指定类名称来动态加载类。

只展示核心代码块
public static void main(String[] args) {
    try {
        Class clz = Class.forName(args[0]);
        out.println("类名称:" + clz.getName());
    }
}

forName的另一个重载函数是可以指定是否在加载.class文档时是否就执行类内部的静态块。Class clz = Class.forName("liujinliang.package.jdbc", false, jdbc.getClassLoader();

从Class获取信息

package refDemo;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;

public class ClassViewer {
    public static void main(String[] args) {
        try {
            ClassViewer.view("java.lang.String");
        } catch (ArrayIndexOutOfBoundsException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    public static void view(String clzName) throws ClassNotFoundException {
        Class clz = Class.forName(clzName);
        showPackageInfo(clz);
        showClassInfo(clz);

        System.out.println("{");

        showFieldsInfo(clz);
        showConstructorsInfo(clz);
        showMethodsInfo(clz);

        System.out.println("}");
    }

    /**
     * 包对应的类型是java.lang.Package
     * @param clz
     */
    public static void showPackageInfo(Class clz) {
        Package p = clz.getPackage();   //取得包代表对象
        System.out.println("package:" + p.getName());
    }

    public static void showClassInfo(Class clz) {
        int modifier = clz.getModifiers();  //取得类型修饰常数
        System.out.println(clz.getName() + "|" + Modifier.toString(modifier) + "|" + (Modifier.isInterface(modifier) ? "interface" : "class"));
    }

    public static void showFieldsInfo(Class clz) {
        // 取得声明的数据成员的代表对象
        Field[] fields = clz.getDeclaredFields();
        for (Field field : fields) {
            // 显示权限修饰,例如public、protected、private
            System.out.println(Modifier.toString(field.getModifiers()) + " " + field.getType().getName() + " " + field.getName());
        }
    }

    public static void showConstructorsInfo(Class clz) {
        // 取得声明的构造方法代表对象
        Constructor[] constructors = clz.getConstructors();

        for (Constructor constructor : constructors ) {
            System.out.println(Modifier.toString(constructor.getModifiers()) + " " + constructor.getName());
        }
    }

    public static void showMethodsInfo(Class clz) {
        Method[] methods = clz.getMethods();
        for (Method method : methods) {
            System.out.println(Modifier.toString(method.getModifiers()) + " " + method.getReturnType().getName() + " " + method.getName());
        }
    }
}

从Class建立对象

package student;

public class Student {
    private String name;
    private Integer score;

    public Student() {
    }

    public Student(String name, Integer score) {
        this.name = name;
        this.score = score;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getScore() {
        return score;
    }

    public void setScore(Integer score) {
        this.score = score;
    }

    @Override
    public String toString() {
        return name + ":" + score;
    }

}
核心代码块
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;


public class TestStudent {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
        Class clz = Class.forName("student.Student");
        Constructor constructor = clz.getConstructor(String.class, Integer.class);
        Object obj = constructor.newInstance("Liujinliang", 22);
        System.out.println(obj.toString());

        // 操作对象方法与成员
        Method setter = clz.getMethod("setName", String.class);
        setter.invoke(obj, "LiuChao");
        Method getter = clz.getMethod("getName");
        System.out.println(getter.invoke(obj));

    }
}

代理

背景

如果需要在执行某个方法前后需要进行日志记录,你可能会这样撰写:

class HelloSpeaker {
    public void hello(String name) {
        // 方法开始前留下日志
        Logger.getLogger(HelloSpeaker.class.getName()).log(Level.INFO, "hello()方法开始");;

        // 程序主要功能
        System.out.println("Hello:" + name);

        // 方法执行完毕前留下日志
        Logger.getLogger(HelloSpeaker.class.getName()).log(Level.INFO,"hello()方法结束");
    }
}

如果希望为许多方法都添加日志,或者有一天觉得这些日志比较多余,是不是会觉得添加和删除的代码两会比较烦啊。这就引入了下面将要说的静态代理和动态代理。动态代理比静态代理的优势就是:可以让你不必为特定接口操作特定代理对象,使用动态代理,可使用一个处理者代理多个接口的操作对象。

静态代理

还记不记得之前说过的向上转型啊,这就是一个典型的应用,当然了,从多态的角度来看,就叫运行时多态,真正调用的方法是子类重写父类的方法,在代理类中,真正调用的是别代理对象的相关方法,静态代理的主要缺点就是,一个接口对应一个代理类(特定接口对应特定代理类)。

package proxy;

public interface Hello {
    void hello(String name);
}
package proxy;

public class HelloSpeaker implements Hello {

    @Override
    public void hello(String name) {
        System.out.println("Hello:" + name);
        System.out.println("I'm Liujinliang");
    }

}
package proxy;

import java.util.logging.Level;
import java.util.logging.Logger;

public class HelloProxy implements Hello {

    private Hello helloObj;

    public HelloProxy(Hello helloObj) {
        this.helloObj = helloObj;
    }

    @Override
    public void hello(String name) {
        // 方法开始前留下日志
        log("hello()方法开始");

        // 程序主要功能
        helloObj.hello(name);

        // 方法执行完毕前留下日志
        log("hello()方法结束");

    }

    private void log(String msg) {

        Logger.getLogger(HelloSpeaker.class.getName()).log(Level.INFO, msg);

    }

    public static void main(String[] args) {
        Hello helloProxy = new HelloProxy(new HelloSpeaker());
        helloProxy.hello("Liujinliang");
    }
}

动态代理

为了解决一个接口一个代理类的局限性,我们想到了动态代理。

package proxy;

public class HelloSpeaker implements Hello {

    @Override
    public void hello(String name) {
        System.out.println("Hello:" + name);
        System.out.println("I'm Liujinliang");
    }

}
package proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.logging.Level;
import java.util.logging.Logger;

public class LoggingHandler implements InvocationHandler {

    private Object target;

    public Object bind(Object target) {
        this.target = target;
        return Proxy.newProxyInstance(
                target.getClass().getClassLoader(),
                target.getClass().getInterfaces(),
                this);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {

        Object res = null;

        Logger.getLogger(LoggingHandler.class.getName()).log(Level.INFO, method.getName() + "呼叫开始。。。");
        res = method.invoke(target, args);
        Logger.getLogger(LoggingHandler.class.getName()).log(Level.INFO, method.getName() + "呼叫结束。。。");

        return res;
    }

    public static void main(String[] args) {
        LoggingHandler loggingHandler = new LoggingHandler();
        Hello proxy = (Hello) loggingHandler.bind(new HelloSpeaker());
        proxy.hello("Liujinliang");
    }
}

猜你喜欢

转载自blog.csdn.net/qq_20330063/article/details/80389737