Java核心笔记

                         Java核心笔记编程

1、

Java 网络编程:

网络编程是指编写运行在多个设备(计算机)的程序,这些设备都通过网络连接起来。

java.net 包中提供了两种常见的网络协议的支持:

TCP:TCP(英语:Transmission Control Protocol,传输控制协议) 是一种面向连接的、可靠的、基于字节流的传输层通信协议,TCP 层是位于 IP 层之上,应用层之下的中间层。TCP 保障了两个应用程序之间的可靠通信。通常用于互联网协议,被称 TCP / IP。

UDP:UDP (英语:User Datagram Protocol,用户数据报协议),位于 OSI 模型的传输层。一个无连接的协议。提供了应用程序之间要发送数据的数据报。由于UDP缺乏可靠性且属于无连接协议,所以应用程序通常必须容许一些丢失、错误或重复的数据包。

2、

Socket 编程:

套接字使用TCP提供了两台计算机之间的通信机制。 客户端程序创建一个套接字,并尝试连接服务器的套接字。当连接建立时,服务器会创建一个 Socket 对象。客户端和服务器现在可以通过对 Socket 对象的写入和读取来进行通信。java.net.Socket 类代表一个套接字,并且 java.net.ServerSocket 类为服务器程序提供了一种来监听客户端,并与他们建立连接的机制。

以下步骤在两台计算机之间使用套接字建立TCP连接时会出现:

a、服务器实例化一个 ServerSocket 对象,表示通过服务器上的端口通信。

b、服务器调用 ServerSocket 类的 accept() 方法,该方法将一直等待,直到客户端连接到服务器上给定的端口。

c、服务器正在等待时,一个客户端实例化一个 Socket 对象,指定服务器名称和端口号来请求连接。

d、Socket 类的构造函数试图将客户端连接到指定的服务器和端口号。如果通信被建立,则在客户端创建一个 Socket 对象能够 与服务器进行通信。

e、在服务器端,accept() 方法返回服务器上一个新的 socket 引用,该 socket 连接到客户端的 socket。

连接建立后,通过使用 I/O 流在进行通信,每一个socket都有一个输出流和一个输入流,客户端的输出流连接到服务器端的输入流,而客户端的输入流连接到服务器端的输出流。

TCP 是一个双向的通信协议,因此数据可以通过两个数据流在同一时间发送.以下是一些类提供的一套完整的有用的方法来实现 socket。

Java的网络编程主要涉及到的内容是Socket编程。Socket,套接字,就是两台主机之间逻辑连接的端点。TCP/IP协议是传输层协议,主要解决数据如何在网络中传输,而HTTP是应用层协议,主要解决如何包装数据。Socket是通信的基石,是支持TCP/IP协议的网络通信的基本操作单元。它是网络通信过程中端点的抽象表示,包含进行网络通信必须的五种信息:连接使用的协议、本地主机的IP地址、本地进程的协议端口、远程主机的IP地址、远程进程的协议端口。

Socket,实际上是对TCP/IP协议的封装,Socket本身并不是协议,而是一个调用接口(API),通过Socket,我们才能使用TCP/IP协议。实际上,Socket跟TCP/IP协议没有必然的关系,Socket编程接口在设计的时候,就希望也能适应其他的网络协议。所以说,Socket的出现,只是使得程序员更方便地使用TCP/IP协议栈而已,是对TCP/IP协议的抽象,从而形成了我们知道的一些最基本的函数接口,比如create、listen、accept、send、read和write等等。网络有一段关于socket和TCP/IP协议关系的说法比较容易理解:

 “TCP/IP只是一个协议栈,就像操作系统的运行机制一样,必须要具体实现,同时还要提供对外的操作接口。这个就像操作系统会提供标准的编程接口,比如win32编程接口一样,TCP/IP也要提供可供程序员做网络开发所用的接口,这就是Socket编程接口。”

实际上,传输层的TCP是基于网络层的IP协议的,而应用层的HTTP协议又是基于传输层的TCP协议的,而Socket本身不算是协议,就像上面所说,它只是提供了一个针对TCP或者UDP编程的接口。socket是对端口通信开发的工具,它要更底层一些。

3、

Socket整体流程:

Socket编程主要涉及到客户端和服务端两个方面,首先是在服务器端创建一个服务器套接字(ServerSocket),并把它附加到一个端口上,服务器从这个端口监听连接。端口号的范围是0到65536,但是0到1024是为特权服务保留的端口号,我们可以选择任意一个当前没有被其他进程使用的端口。

客户端请求与服务器进行连接的时候,根据服务器的域名或者IP地址,加上端口号,打开一个套接字。当服务器接受连接后,服务器和客户端之间的通信就像输入输出流一样进行操作。

4、

ServerSocket 类的方法:

服务器应用程序通过使用 java.net.ServerSocket 类以获取一个端口,并且侦听客户端请求。ServerSocket 类有四个构造方法:

a.public ServerSocket(int port) throws IOException----创建绑定到特定端口的服务器套接字。                         

b.public ServerSocket(int port, int backlog) throws IOException-----利用指定的 backlog 创建服务器套接字并将其绑定到指定的本地端口号。

c.public ServerSocket(int port, int backlog, InetAddress address) throws IOException-----使用指定的端口、侦听 backlog 和要绑定到的本地 IP 地址创建服务器。

d.public ServerSocket() throws IOException -----创建非绑定服务器套接字。                                   

创建非绑定服务器套接字。 如果 ServerSocket 构造方法没有抛出异常,就意味着你的应用程序已经成功绑定到指定的端口,并且侦听客户端请求。

5、

这里有一些 ServerSocket 类的常用方法:

a.public int getLocalPort()------返回此套接字在其上侦听的端口。                    

b.public Socket accept() throws IOException------侦听并接受到此套接字的连接。                      

c.public void setSoTimeout(int timeout)------- 通过指定超时值启用/禁用 SO_TIMEOUT,以毫秒为单位。

d.public void bind(SocketAddress host, int backlog)------将 ServerSocket 绑定到特定地址(IP 地址和端口号)。

6、

Socket 类的方法:

java.net.Socket 类代表客户端和服务器都用来互相沟通的套接字。客户端要获取一个 Socket 对象通过实例化 ,而 服务器获得一个 Socket 对象则通过 accept() 方法的返回值。

7、

Socket 类有五个构造方法:

1.public Socket(String host, int port) throws UnknownHostException, IOException.------创建一个流套接字并将其连接到指定主机上的指定端口号。   

2.public Socket(InetAddress host, int port) throws IOException-----创建一个流套接字并将其连接到指定 IP 地址的指定端口号。 

3.public Socket(String host, int port, InetAddress localAddress, int localPort) throws IOException.-----创建一个套接字并将其连接到指定远程主机上的指定远程端口。

4.public Socket(InetAddress host, int port, InetAddress localAddress, int localPort) throws IOException.------创建一个套接字并将其连接到指定远程地址上的指定远程端口。

5.public Socket()------通过系统默认类型的 SocketImpl 创建未连接套接字         

当 Socket 构造方法返回,并没有简单的实例化了一个 Socket 对象,它实际上会尝试连接到指定的服务器和端口。

下面列出了一些感兴趣的方法,注意客户端和服务器端都有一个 Socket 对象,所以无论客户端还是服务端都能够调用这些方法。

1.public void connect(SocketAddress host, int timeout) throws IOException------将此套接字连接到服务器,并指定一个超时值。          

2.public InetAddress getInetAddress()------返回套接字连接的地址。                              

3.public int getPort()-------返回此套接字连接到的远程端口。                      

4.public int getLocalPort()------返回此套接字绑定到的本地端口。                      

5.public SocketAddress getRemoteSocketAddress()-------返回此套接字连接的端点的地址,如果未连接则返回 null。

6.public InputStream getInputStream() throws IOException------返回此套接字的输入流。                              

7.public OutputStream getOutputStream() throws IOException------返回此套接字的输出流。                              

8.public void close() throws IOException------关闭此套接字。                                      

InetAddress 类的方法

这个类表示互联网协议(IP)地址。下面列出了 Socket 编程时比较有用的方法:

1.static InetAddress getByAddress(byte[] addr)------在给定原始 IP 地址的情况下,返回 InetAddress 对象。

2.static InetAddress getByAddress(String host, byte[] addr)------根据提供的主机名和 IP 地址创建 InetAddress。      

3.static InetAddress getByName(String host)------在给定主机名的情况下确定主机的 IP 地址。          

4.String getHostAddress()------返回 IP 地址字符串(以文本表现形式)。            

5.String getHostName()------获取此 IP 地址的主机名。                          

6.static InetAddress getLocalHost()------返回本地主机。                                    

7.String toString()------将此 IP 地址转换为 String。

反射

反射概念

Java 反射机制是 Java 语言的一个重要特性。在学习 Java 反射机制前,先了解两个概念,编译期和运行期。

编译期是指把源码交给编译器编译成计算机可以执行的文件的过程。在 Java 中也就是把 Java 代码编成 class 文件的过程。编译期只是做了一些翻译功能,并没有把代码放在内存中运行起来,而只是把代码当成文本进行操作,比如检查错误。

运行期是把编译后的文件交给计算机执行,直到程序运行结束。所谓运行期就把在磁盘中的代码放到内存中执行起来。

Java 反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为 Java 语言的反射机制。简单来说,反射机制指的是程序在运行时能够获取自身的信息。在 Java 中,只要给定类的名字,就可以通过反射机制来获得类的所有信息。

Java 反射机制在服务器程序和中间件程序中得到了广泛运用。在服务器端,往往需要根据客户的请求,动态调用某一个对象的特定方法。此外,在 ORM 中间件的实现中,运用 Java 反射机制可以读取任意一个 JavaBean 的所有属性,或者给这些属性赋值。

​Java 反射机制主要提供了以下功能,这些功能都位于java.lang.reflect包。

​                            1、在运行时判断任意一个对象所属的类。

​                            2、在运行时构造任意一个类的对象。

​                            3、在运行时判断任意一个类所具有的成员变量和方法。

​                            4、在运行时调用任意一个对象的方法。

​                            5、生成动态代理。

要想知道一个类的属性和方法,必须先获取到该类的字节码文件对象。获取类的信息时,使用的就是 Class 类中的方法。所以先要获取到每一个字节码文件(.class)对应的 Class 类型的对象.

众所周知,所有 Java 类均继承了 Object 类,在 Object 类中定义了一个 getClass() 方法,该方法返回同一个类型为 Class 的对象。例如,下面的示例代码:

Class demo = new Demo01().getClass();  

​利用 Class 类的对象 demo 可以访问 Demo01 对象的描述信息、Demo01 类的信息以及基类 Object 的信息。下表列出了通过反射可以访问的信息。

​如上表所示,在调用 getFields() 和 getMethods() 方法时将会依次获取权限为 public 的字段和变量,然后将包含从超类中继承到的成员变量和方法。而通过 getDeclareFields() 和 getDeclareMethod() 只是获取在本类中定义的成员变量和方法。

Java 反射机制的优缺点

优点:

能够运行时动态获取类的实例,大大提高系统的灵活性和扩展性。

与 Java 动态编译相结合,可以实现无比强大的功能。

对于 Java 这种先编译再运行的语言,能够让我们很方便的创建灵活的代码,这些代码可以在运行时装配,无需在组件之间进行源代码的链接,更加容易实现面向对象。

缺点:

反射会消耗一定的系统资源,因此,如果不需要动态地创建一个对象,那么就不需要用反射;

​反射调用方法时可以忽略权限检查,获取这个类的私有方法和属性,因此可能会破坏类的封装性而导致安全问题。

Java 反射机制在一般的 Java 应用开发中很少使用,即便是 Java EE 阶段也很少使用。

反射机制API

实现 Java 反射机制的类都位于 java.lang.reflect 包中,java.lang.Class 类是 Java 反射机制 API 中的核心类。

java.lang.Class 类

java.lang.Class 类是实现反射的关键所在,Class 类的一个实例表示 Java 的一种数据类型,包括类、接口、枚举、注解(Annotation)、数组、基本数据类型和 void。Class 没有公有的构造方法,Class 实例是由 JVM 在类加载时自动创建的。

每一种类型包括类和接口等,都有一个 class 静态变量可以获得 Class 实例。另外,每一个对象都有 getClass() 方法可以获得 Class 实例,该方法是由 Object 类提供的实例方法。

Class 类提供了很多方法可以获得运行时对象的相关信息.如下所示:

System.out.println("clz2类名称:" + clz2.getName());

        System.out.println("clz2是否为接口:" + clz2.isInterface());

        System.out.println("clz2是否为数组对象:" + clz2.isArray());

        System.out.println("clz2父类名称:" + clz2.getSuperclass().getName());

        System.out.println("clz2是否为基本类型:" + clz2.isPrimitive());

        System.out.println("clz3是否为基本类型:" + clz3.isPrimitive());

        System.out.println("clz4是否为基本类型:" + clz4.isPrimitive());

java.lang.reflect 包

java.lang.reflect 包提供了反射中用到类,主要的类说明如下:

 Constructor 类:提供类的构造方法信息。

 Field 类:提供类或接口中成员变量信息。

 Method 类:提供类或接口成员方法信息。

 Array 类:提供了动态创建和访问 Java 数组的方法。

 Modifier 类:提供类和成员访问修饰符信息。

通过反射访问构造方法

为了能够动态获取对象构造方法的信息,首先需要通过下列方法之一创建一个 Constructor 类型的对象或者数组。

​                            getConstructors()

​                            getConstructor(Class<?>…parameterTypes)

​                            getDeclaredConstructors()

​                            getDeclaredConstructor(Class<?>...parameterTypes)

如果是访问指定的构造方法,需要根据该构造方法的入口参数的类型来访问。例如,访问一个入口参数类型依次为 int 和 String 类型的构造方法,下面的两种方式均可以实现。

objectClass.getDeclaredConstructor(int.class,String.class);

objectClass.getDeclaredConstructor(new Class[]{int.class,String.class});

创建的每个 Constructor 对象表示一个构造方法,然后利用 Constructor 对象的方法操作构造方法。Constructor 类的常用方法如下所示。

1.isVarArgs()------查看该构造方法是否允许带可变数量的参数,如果允许,返回 true,否则返回 false

2.getParameterTypes()-------按照声明顺序以 Class 数组的形式获取该构造方法各个参数的类型

3.getExceptionTypes()-------以 Class 数组的形式获取该构造方法可能抛出的异常类型        

4.newInstance(Object … initargs)------通过该构造方法利用指定参数创建一个该类型的对象,如果未设置参数则表示 采用默认无参的构造方法

5.setAccessiable(boolean flag)------如果该构造方法的权限为 private,默认为不允许通过反射利用 netlnstance() 方法创建对象。如果先执行该方法,并将入口参数设置为 true,则允许创建对象

6.getModifiers()------获得可以解析出该构造方法所采用修饰符的整数                

通过 java.lang.reflect.Modifier 类可以解析出 getMocMers() 方法的返回值所表示的修饰符信息。在该类中提供了一系列用来解析的静态方法,既可以查看是否被指定的修饰符修饰,还可以字符串的形式获得所有修饰符。表 2 列出了 Modifier 类的常用静态方法。

1.isStatic(int mod)-----如果使用 static 修饰符修饰则返回 true,否则返回 false  

2.isPublic(int mod)-----如果使用 public 修饰符修饰则返回 true,否则返回 false  

3.isProtected(int mod)-----如果使用 protected 修饰符修饰则返回 true,否则返回 false

4.isPrivate(int mod) -----如果使用 private 修饰符修饰则返回 true,否则返回 false  

5.isFinal(int mod)-----如果使用 final 修饰符修饰则返回 true,否则返回 false   

6.toString(int mod)------以字符串形式返回所有修饰符                                                

通过反射执行方法

要动态获取一个对象方法的信息,首先需要通过下列方法之一创建一个 Method 类型的对象或者数组。

​                            getMethods()

​                            getMethods(String name,Class<?> …parameterTypes)

​                            getDeclaredMethods()

​                            getDeclaredMethods(String name,Class<?>...parameterTypes)

如果是访问指定的构造方法,需要根据该方法的入口参数的类型来访问。例如,访问一个名称为 max,入口参数类型依次为 int 和 String 类型的方法。

下面的两种方式均可以实现:

objectClass.getDeclaredConstructor("max",int.class,String.class);

objectClass.getDeclaredConstructor("max",new Class[]{int.class,String.class});

Method 类的常用方法如下所示。

1.getName()-----获取该方法的名称                                           

2.getParameterType()-----按照声明顺序以 Class 数组的形式返回该方法各个参数的类型    

3.getReturnType()-----以 Class 对象的形式获得该方法的返回值类型                  

4.getExceptionTypes()------以 Class 数组的形式获得该方法可能抛出的异常类型            

5.invoke(Object obj,Object...args)------利用 args 参数执行指定对象 obj 中的该方法,返回值为 Object 类型

6.isVarArgs()-----查看该方法是否允许带有可变数量的参数,如果允许返回 true,否则返回 false

7.getModifiers()-----获得可以解析出该方法所采用修饰符的整数 

通过反射访问成员变量

通过下列任意一个方法访问成员变量时将返回 Field 类型的对象或数组。

​                            getFields()

​                            getField(String name)

​                            getDeclaredFields()

​                            getDeclaredField(String name)

上述方法返回的 Field 对象代表一个成员变量。例如,要访问一个名称为 price 的成员变量,示例代码如下:

object.getDeciaredField("price");

Field 类的常用方法如下所示

1.getName()-----获得该成员变量的名称                                       

2.getType()-----获取表示该成员变量的 Class 对象                             

3.get(Object obj)-----获得指定对象 obj 中成员变量的值,返回值为 Object 类型      

4.set(Object obj, Object value)-----将指定对象 obj 中成员变量的值设置为 value                  

5.getlnt(0bject obj)-----获得指定对象 obj 中成员类型为 int 的成员变量的值           

6.setlnt(0bject obj, int i)-----将指定对象 obj 中成员变量的值设置为 i                       

7.setFloat(Object obj, float f)-----将指定对象 obj 中成员变量的值设置为 f                      

8.getBoolean(Object obj)-----获得指定对象 obj 中成员类型为 boolean 的成员变量的值       

9.setBoolean(Object obj, boolean b)-----将指定对象 obj 中成员变量的值设置为 b                      

10.getFloat(Object obj)-----获得指定对象 obj 中成员类型为 float 的成员变量的值         

11.setAccessible(boolean flag)-----此方法可以设置是否忽略权限直接访问 private 等私有权限的成员变量

12.getModifiers()-----获得可以解析出该方法所采用修饰符的整数 

获取继承关系

当我们获取到某个`Class`对象时,实际上就获取到了一个类的类型:

Class cls = String.class; // 获取到String的Class

还可以用实例的`getClass()`方法获取:

String s = "";

Class cls = s.getClass(); // s是String,因此获取到String的Class

最后一种获取`Class`的方法是通过`Class.forName("")`,传入`Class`的完整类名获取:

Class s = Class.forName("java.lang.String");

这三种方式获取的`Class`实例都是同一个实例,因为JVM对每个加载的`Class`只创建一个`Class`实例来表示它的类型。

`Integer`实现的接口有:

java.lang.Comparable

java.lang.constant.Constable

java.lang.constant.ConstantDesc

要特别注意:`getInterfaces()`只返回当前类直接实现的接口类型,并不包括其父类实现的接口类型

如果一个类没有实现任何`interface`,那么`getInterfaces()`返回空数组。

小结

通过`Class`对象可以获取继承关系:

 Class getSuperclass():获取父类类型;

 Class[] getInterfaces():获取当前类实现的所有接口。

通过`Class`对象的`isAssignableFrom()`方法可以判断一个向上转型是否可以实现。

动态代理

我们来比较Java的`class`和`interface`的区别:

可以实例化`class`(非`abstract`);

不能实例化`interface`。

所有`interface`类型的变量总是通过某个实例向上转型并赋值给接口类型变量的:

CharSequence cs = new StringBuilder();

Java标准库提供了一种动态代理(Dynamic Proxy)的机制:可以在运行期动态创建某个interface的实例。

所谓动态代理,是和静态相对应的。静态代码怎么写,如下:

定义接口:

public interface Hello {

    void morning(String name);

}

编写实现类:

public class HelloWorld implements Hello {

    public void morning(String name) {

        System.out.println("Good morning, " + name);

    }

}

创建实例,转型为接口并调用:

Hello hello = new HelloWorld();

hello.morning("Bob");

这种方式就是通常编写代码的方式。

JDK提供的动态创建接口对象的方式,就叫动态代理。

在运行期动态创建一个`interface`实例的方法如下:

​                            1、定义一个InvocationHandler实例,它负责实现接口的方法调用;

​                            2、通过Proxy.newProxyInstance()创建interface实例,它需要3个参数:

​                                          2.1、使用的ClassLoader,通常就是接口类的ClassLoader;

​                                          2.2、需要实现的接口数组,至少需要传入一个接口进去;

​                                          2.3、用来处理接口方法调用的InvocationHandler实例。

​                            3、将返回的Object强制转型为接口。

​动态代理实际上是JVM在运行期动态创建class字节码并加载的过程

​              其实就是JVM帮我们自动编写了一个上述类(不需要源码,可以直接生成字节码)。

小结

Java标准库提供了动态代理功能,允许在运行期动态创建一个接口的实例;

动态代理是通过`Proxy`创建代理对象,然后将接口方法“代理”给`InvocationHandler`完成的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值