我爱编程

Java知识点总结

2018-03-15  本文已影响47人  andpy

JAVA知识点概括

BIO

阻塞式IO(BIO):数据在写入OutputStream或者InputStream都有可能会阻塞。如ServiceSocket在调用accept时,有客服端链接时,才会返回。一般连接之后会提供单独的线程去处理请求,当客服端大量的时候,存在大量线程,耗费资源,加重cpu的负担
弊端:

客服端链接

 //创建客户端socket,指定ip和端口
    Socket socket = new Socket("localhost",10086);
    //获取输入流,向服务器发送信息
    //字节流
    OutputStream os = socket.getOutputStream();
    //封装为打印流
    PrintWriter pw = new PrintWriter(os);
    pw.write("我是socket 客户端");
    //刷新
    pw.flush();
    socket.shutdownOutput();
    //获取输入流,读取服务器响应信息
    InputStream is = socket.getInputStream();
    BufferedReader br = new BufferedReader(new InputStreamReader(is));
    String info = null;
    while ((info=br.readLine())!=null){
        System.out.println("客户端:服务端发来的信息"+info);
    }
    br.close();
    is.close();
    pw.close();
    os.close();
    socket.close();

服务器端连接

 //创建socket服务器端,端口
    ServerSocket serverSocket = new ServerSocket(10086);
    //调用accept方法,开始监听
    Socket socket = serverSocket.accept();
    //获取输入流
    InputStream is = socket.getInputStream();
    InputStreamReader isr = new InputStreamReader(is);
    BufferedReader br = new BufferedReader(isr);
    String info = null;
    while ((info =br.readLine())!=null){
        System.out.println("我是服务端:客服端发来消息:"+info);
    }
    socket.shutdownOutput();
    //后去输入流响应请求
    OutputStream os = socket.getOutputStream();
    PrintWriter pw = new PrintWriter(os);
    pw.write("欢迎你");
    pw.flush();

    pw.close();
    os.close();
    br.close();
    isr.close();
    socket.close();
    serverSocket.close();

url

统一资源定位符,这个介绍简单使用,具体的没研究

public static void testURL() throws IOException {
    URL url = new URL("https://www.baidu.com/");
    InputStream inputStream = url.openStream();
    InputStreamReader reader = new InputStreamReader(inputStream, "utf-8");
    BufferedReader bufferedReader = new BufferedReader(reader);
    String line = bufferedReader.readLine();
    while (line != null) {
        System.out.println(line);
        line = bufferedReader.readLine();
    }
    inputStream.close();
    reader.close();
    bufferedReader.close();

}

Java高级IO

NIO

通信模型:

客服端code:

public class NIOClient {
//通道管理器
private Selector selector;

/**
 * 获取一个Socket通道,并对该通道做了一些初始化的操作
 *
 * @param ip
 * @param port
 * @throws IOException
 */
public void initClient(String ip, int port) throws IOException {
    //获得一个Socket通道
    SocketChannel channel = SocketChannel.open();
    //设置通道为非阻塞
    channel.configureBlocking(false);
    //获取通道管理器
    this.selector = Selector.open();
    //客服端连接服务器,其实方法执行并没有实现连接,需要在listen()方法中调
    //用channel.finishConnect() 才能完成连接
    channel.connect(new InetSocketAddress(ip, port));
    //将通道管理器和该通道绑定,并为该通道注册SelectionKey.OP_CONNECT事件
    channel.register(selector, SelectionKey.OP_CONNECT);
}

/**
 * 轮询的方式监听 Selector是否有需要处理的事件,有则进行处理
 */
public void listen() throws IOException {
    //轮询访问selector
    while (true) {
        selector.select();
        //获得selector中选中的项的迭代器
        Iterator<SelectionKey> ite = this.selector.selectedKeys().iterator();
        while (ite.hasNext()) {
            SelectionKey key = ite.next();
            //删除已选的key,防止重复处理
            ite.remove();
            //连接事件发生
            if (key.isConnectable()){
               SocketChannel channel = (SocketChannel) key.channel();
               //如果正在连接,则完成连接
                if (channel.isConnectionPending()){
                    channel.finishConnect();
                }
                //设置程非阻塞
                channel.configureBlocking(false);
                //在这里给服务端发送信息
                channel.write(ByteBuffer.wrap(new String("向服务器发送了信息").getBytes("utf-8")));
                //在和服务端连接成功之后,为了可以收到服务端信息,需要给通道设置权限
                channel.register(this.selector,SelectionKey.OP_READ);
            }else if (key.isReadable()){
                read(key);
            }
        }
    }
}

private void read(SelectionKey key) throws IOException {
    //读取消息,得到发生的socket通道
    SocketChannel channel = (SocketChannel) key.channel();
    //创建缓冲区
    ByteBuffer buffer = ByteBuffer.allocate(1024);
    channel.read(buffer);
    byte[] data = buffer.array();
    String msg = new String(data).trim();
    System.out.println("client: "+msg);
}
}

服务端code:

public class NIOService {
    //通道管理器
    private Selector selector;

    public void initServer(int port) throws IOException {
        //获得一个ServerSocket通道
        ServerSocketChannel serverChannel = ServerSocketChannel.open();
        //设置非阻塞
        serverChannel.configureBlocking(false);
        //绑定到该端口
        serverChannel.socket().bind(new InetSocketAddress(port));
        //获得通道管理器
        this.selector = Selector.open();
        //将该通道和该通道绑定,并为该通道注册SelectionKey.OP_ACCEPT事件
        //注册事件后,当该事件到达时,selector.select()会返回,如果该事件没有
        //达到selector.select()会一直阻塞
        serverChannel.register(selector, SelectionKey.OP_ACCEPT);
    }

    public void listen() throws IOException {
        System.out.println("服务端启动");
        //轮询
        while (true) {
            //注册事件到达时会返回,否则该方法会一直阻塞
            selector.select();
            //获得selector中的项的迭代器,选中的项为注册的事件
            Iterator<SelectionKey> ite = this.selector.selectedKeys().iterator();
            while (ite.hasNext()) {
                SelectionKey key = ite.next();
                //删除已选的key,以防重复处理
                ite.remove();
                //客服端请求连接事件
                if (key.isAcceptable()) {
                    ServerSocketChannel server = (ServerSocketChannel) key.channel();
                    //获得和客服端的连接的通道
                    SocketChannel channel = server.accept();
                    //设置非阻塞
                    channel.configureBlocking(false);
                    //在这里可以给客服端发送信息
                    channel.write(ByteBuffer.wrap(new String("服务器发送信息").getBytes("utf-8")));
                    //在和客服端连接成功之后,为了可以接受到客服端的信息,需要给通道设置读的权限
                    channel.register(this.selector, SelectionKey.OP_READ);
                } else if (key.isReadable()) {
                    read(key);
                }
            }
        }
    }

    private void read(SelectionKey key) throws IOException {
        //读取消息,得到发生的socket通道
        SocketChannel channel = (SocketChannel) key.channel();
        //创建缓冲区
        ByteBuffer buffer = ByteBuffer.allocate(10);
        channel.read(buffer);
        byte[] data = buffer.array();
        String msg = new String(data).trim();
        System.out.println("service: "+msg);
    }

}

多线程

共同点:通过thrad创建线程,通过start()方法开启就绪状态(具体的启动是有操作系统来决定的),直接调用run方法,没有线程效果,就是调用普通的方法。

//通过集成的方式
 ThreadByExtends threadByExtends = new ThreadByExtends();
 threadByExtends.start();
//通过实现的方式
 ThreadImpByRunnable threadImpByRunnable = new ThreadImpByRunnable();
 Thread thread = new Thread(threadImpByRunnable);
 thread.start();

线程间通信

synchronized关键字

线程池

/**
线程的基本大小
线程池最大线程数量,超过这个线程将不再创建线程
线程活动保持的时间,在适当时间线程可以复用
时间单位
当线程满了之后,会等待,之后放入对列中执行
创建线程的工厂
保护策略,当线程和队列满了之后的处理 AbortPolicy满了之后抛异常
*/
public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
                          BlockingQueue<Runnable> workQueue,
                          ThreadFactory threadFactory,
                          RejectedExecutionHandler handler)

线程池的工作流程

异常

异常处理机制

原理

异常处理

 try {
        return 0;
    } catch (Exception e) {

    } finally {
    
    }
    return 0;
Java中检查型异常和非检查型异常有什么区别?
Java检查型异常:对于申明抛出异常的方法,编译器将进行强制的处理
非检查型异常: error,runtimeexception

throw和throws两个关键字在java中有什么不同?
throws 出现在方法头部,表明该异常不能处理
throw: 方法内,抛出一个具体的异常

如果执行finally代码块之前方法返回的结果,或者jvm退出了,finally块中的代码会执行吗?
前者会执行,后者不会执行

Java中final,finalize,finally关键字区别
final:修饰符的关键字, 修饰类不能被继承,修饰变量必须初始化值,不能改变
finalize:方法名,jvm将在垃圾收集器的时候,将对象从内存清除出去.

注解

注解:Annotation(注解) 就是Java提供了一种元程序中的元素关联任何信息和着任何元数据(metadata)的途径和方法。
基本的规则:Annotation 不能影响程序代码的执行,无论增加,删除 Annotation,代码都始终如一的执行。
metadata(元数据):描述数据的数据,代码之间的关系。

元数据以标签的形式存在于java代码中
元数据描述的信息是类型安全的
元数据需要编译器之外的工具额外的处理用来生成其它的程序部件.
元数据可以存在Java源代码级别,也可以存在编译之后的class文件内部

系统注解

@SuppressWarnings(value="unchecked")

元注解:

//修饰对象的范围
@Target(ElementType.FIELD)
//对象的生命周期
@Retention(RetentionPolicy.RUNTIME)
//程序的api
@Documented
//标注的类型是否可以被继承
@Inherited
public @interface Column {
}

Android support annotations
api 19出现的库

ClassLoader

程序通过程序的需要,通过类的加载机制逐渐加载指定的class文件
开发人员来看:

双亲委托模型

类加载的过程

静态绑定:程序执行方法以前,是有编译器连接该方法
动态绑定:是在运行是有类去动态绑定。

Java堆和栈

静态分配(方法区):主要存放静态数据,全局static数据和常量,在整个程序期间都会存在。

栈分配 :方法执行时,局部变量在栈上创建区域,执行完毕后,会清楚,效率高但容量有限。

堆分配 :通常指的是在程序运行时直接new出来的内存

java垃圾回收机制
java内存泄漏的原因

反射

编译:将java代码转换为 .class文件,只纠正语法

运行:java虚拟机执行 .class文件的过程

在调用引用实例的成员变量,无论是编译时,还是运行时,均是调用编译时类型的成员变量。

反射:在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能调用它的任意一个方法和属性。

生成一个.class文件,就会在 .class文件中生成一个 Class对象
获取class的三种方式

    //方式一
    Person person = new Person();
    Class<? extends Person> clazz = person.getClass();
    //获取包名和类名
    System.out.println("包名:" + clazz.getPackage().getName() + " 完成类名: " + clazz.getName());
    //方式二
    Class<?> clazz1 = Class.forName("reflex.Person");
    //创建对象
    Person instance = (Person) clazz1.newInstance();
    instance.setAge(10);
    instance.setName("张三");
    System.out.println(instance.toString());
    //得到构造函数,创建对象
    Constructor<?>[] constructors = clazz1.getConstructors();
    Person person1 = (Person) constructors[0].newInstance();
    //有参构造
    Person person2 = (Person) constructors[1].newInstance("张三", 100);
    //反射调用方法
    Method getName = clazz1.getMethod("getName");
    //有参函数
    Method setName = clazz1.getMethod("setName", String.class);
    setName.invoke(clazz1.newInstance(), "王武");
    getName.invoke(clazz1.newInstance());
    //方式三
    Class<Person> calzz2 = Person.class;

Android反射相关

通过原始的java反射机制的方式调用资源,在调用三方的R文件的时候,通过反射获取!
定义一个资源工具类:

public class ResourceHelper {
    private static String mPackageName = null;
    private static Class<?> mLayout = null;
    private static Class<?> mDrawable = null;
    private static Class<?> mId = null;
    private static Class<?> mAttr = null;

    private static ResourceHelper mResourceHelper = null;

    public static ResourceHelper newInstance(Context context) {
        if (mResourceHelper == null) {
            mPackageName = (mPackageName == null) ? context.getPackageName() : mPackageName;
            mResourceHelper = new ResourceHelper(mPackageName);
        }
        return mResourceHelper;
    }

    public ResourceHelper(String packageName) {
        try {
            mLayout = Class.forName(mPackageName + ".R$layout");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        try {
            mDrawable = Class.forName(mPackageName + ".R$drawable");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        try {
            mId = Class.forName(mPackageName + ".R$id");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        try {
            mAttr = Class.forName(mPackageName + ".R$attr");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

    }

    private int getResourceId(Class<?> classtType, String resourceName) {
        if (classtType == null) {
            throw new IllegalArgumentException("resclass is not initialized");
        }
        try {
            Field field = classtType.getField(resourceName);
            return field.getInt(resourceName);
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return -1;
    }

    public int getDrawableId(String resourceName) {
        return getResourceId(mDrawable, resourceName);
    }

    public int getLayoutId(String resourceName) {
        return getResourceId(mLayout, resourceName);
    }

    public int getId(String resourceName) {
        return getResourceId(mId, resourceName);
    }

    public int getAttrId(String resourcename) {
        return getResourceId(mAttr, resourcename);
    }

测试验证在activiyt中

   setContentView(ResourceHelper.newInstance(getApplicationContext()).getLayoutId("activity_main"));

Activity的启动过程中Activity的对象的创建
在android源码中 ActivityThread中找到 performLaunchActivity 类

   Activity activity = null;
    try {
        java.lang.ClassLoader cl = appContext.getClassLoader();
        activity = mInstrumentation.newActivity(
                cl, component.getClassName(), r.intent);
        StrictMode.incrementExpectedActivityCount(activity.getClass());
        r.intent.setExtrasClassLoader(cl);
        r.intent.prepareToEnterProcess();
        if (r.state != null) {
            r.state.setClassLoader(cl);
        }
    } catch (Exception e) {
        if (!mInstrumentation.onException(activity, e)) {
            throw new RuntimeException(
                "Unable to instantiate activity " + component
                + ": " + e.toString(), e);
        }
    }

//newActivity方法跟进来,是运用反射的方式加载的
  public Activity newActivity(ClassLoader cl, String className,
        Intent intent)
        throws InstantiationException, IllegalAccessException,
        ClassNotFoundException {
    return (Activity)cl.loadClass(className).newInstance();
}

在xml布局写的标签,等都是通过反射注入到java代码中.

上一篇下一篇

猜你喜欢

热点阅读