Java网络学习之 URL类源码剖析(1)

注:在此用的JDK8的版本。

首先,URL在java.net这个包,类签名如下:
public final class URL implements java.io.Serializable可见URL是一个final类,即URL类无法被继承,并实现了Serializable接口,即URL对象可被序列化。

再看URL主要的实例属性:

private String protocol;

private String host; 
private int port;

private String file; 
private transient String query;

private String authority; 
private transient String path;

private String ref;

容易发现其实它跟URL格式的每一部分一一对应:
scheme:[//[user[:password]@]host[:port]][/path][?query][#fragment]

再看URL类最常用的一个constructor:
public URL(String spec) throws MalformedURLException {

     this(null, spec);

}
public URL(URL context, String spec) throws MalformedURLException {

     this(context, spec, null);

}
它最终会调到下面这个constructor:
public URL(URL context, String spec, URLStreamHandler handler) throws MalformedURLException

那我们就看这个constructor是怎么实现URL的解析的:
它先把头尾的空格去掉,注意,它这里用的判断是<= ' ', 因为在ASCII码中小于空格(32)的都是不可见的字符。
然后判断传入的字符串中是否以url:开头, 如果有,就去掉,所以,如果传入URL字符串是以url:开头的,JDK还是能解析出来的。
接着判断是否相对URL。

然后解析出protocol,方法比较直观,就是第一个:前面的所有字符,并把start变量设置为:后面第一个为开始。这里还验证了一下protocol的格式,验证比较粗糙,只是确保protocol字符串的首字符是字母,并且protocol字符串全部是字母或者数字且不包含'.','+'和'-'。

然后是根据protocol来加载相应的URLStreamHandler:

getURLStreamHandler(protocol)这个方法里核心的代码如下:
可以看到,这里会根据protocol去相应的包里面去加载Handler类,比如,如果protocol是HTTP的,就加载sun.net.www.protocol.http.Handler这个类,并通过反射来new一个实例出来。 接下来就是通过这个Handler来解析和构造这个URL对象了:

这里我们以http协议为例,sun.net.www.protocol.http.Handler这个类是继承java.net.URLStreamHandler,parseURL方法调用的就是URLStreamHandler里面实现的:

先解析出spec,这个spec里面除去了Query查询参数部分,只包含Authority,Host,Port和Path部分:接着就是解析出Authority部分,也就是用户和密码:然后在解析出Path:

最后再调用setURL方法把各部分的值设置好:

setURL方法最后会调用set方法如下:

这里值得注意的是file属性,它设置的是:
this.file = query == null ? path : path + "?" + query;
就是说如果在URL里面指定了query查询参数,那么file就是path?query,如果没有,就是path。我这里为什么要着重强调了这个是因为,这个file属性才是HTTP 请求行中的Path! 如:
GET /hello.jsp?name=Eric HTTP/1.1

URL类源码分析到此为止,接下来我会继续分析Java中如何通过一个URL实例来打开一个connection,然后发送请求的整个过程

public URLConnection openConnection() throws java.io.IOException {
    return handler.openConnection(this);
}
以下是sun.net.www.protocol.http.Handler的源码
package sun.net.www.protocol.http;

import java.io.IOException;
import java.net.Proxy;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLStreamHandler;

public class Handler extends URLStreamHandler {
    protected String proxy;
    protected int proxyPort;

    protected int getDefaultPort() {
        return 80;
    }

    public Handler() {
        this.proxy = null;
        this.proxyPort = -1;
    }

    public Handler(String var1, int var2) {
        this.proxy = var1;
        this.proxyPort = var2;
    }

    protected URLConnection openConnection(URL var1) throws IOException {
        return this.openConnection(var1, (Proxy)null);
    }

    protected URLConnection openConnection(URL var1, Proxy var2) throws IOException {
        return new HttpURLConnection(var1, var2, this);
    }
}

 

可以看到 url.openconnection 其实就是 把当前url 作为一个参数 构造 HttpURLConnection 的过程。

其中streamHandler 的作用就是 解析url,构造connection 

connection 的作用  和远程服务器交互。

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 好的,第1关是学习Java包装之Integer。IntegerJava中的一个包装,用于将基本数据型int封装成一个对象。它提供了很多方法,可以方便地进行数值转换、比较大小、字符串转换等操作。在Java中,我们经常需要将基本数据型转换成对象,或者将对象转换成基本数据型,这时就可以使用Integer来实现。 ### 回答2: Java中的包装是指将基本数据型(如int、float等)封装成对象的,其中,integer是其中常用的包装之一。在Java中,integer提供了很多方便使用的方法,如valueOf()、parseInt()、toString()等。 integer是不能被继承的,同时它也是final的。所以,integer的方法都是静态的。integer主要有两个构造方法:一个是接收int型参数的构造方法,将一个基本数据型封装成integer对象;另一个是接收字符串参数的构造方法,将字符串转换成integer对象。值得注意的是,如果在使用字符串构造方法时字符串包含非数字的字符,就会抛出NumberFormatException异常。 integer的主要用途是在各种算术运算中使用。由于integer是一个包装,所以它可以参与到Java的许多应用程序中,而不必强制使用基本数据型。例如,进行数学操作时,可以使用integer中的各种方法来计算结果,或者将integer对象作为方法参数进行传递。 在使用integer时,还需注意到autoboxing和unboxing这两个概念。autoboxing指的是将基本数据型自动封装成对应的包装型,而unboxing则是将封装型对象自动转换成对应的基本数据型。这两者的作用都是为了在程序中更方便地使用基本数据型和对应的包装型。 总的来说,integer作为Java中常用的包装之一,其作用十分广泛。掌握integer的使用方法,可以更好地进行Java编程,同时也可为后续Java开发工作奠定坚实的基础。 ### 回答3: 在Java中,整数型的数据有byte、short、int和long四种,而IntegerJava中封装了int基本数据型的包装,它提供了一系列用于操作int型的方法,同时也是Java中常用的之一。 Integer中提供的方法可以将一个数字字符串转化成int型,或者从整数中获取一定位数的值,比如getBytes()可以获取int型的最高位字节值。Integer还可以将整数值转换为二进制、八进制或十六进制字符串表示,也可以将字符串表示的数字转换为Integer型。 其中,最常用的操作是将字符串转化为整数型的操作,比如字符串"123"可以使用Integer.parseInt("123")转化为123这个整数型的值。同时,也可以把一个int型的数字转化为它的字符串形式,例如int a=123,可以用String.valueOf(a)或者a.toString()将其转化为字符串"123"。此外,Integer也提供了一些其他型之间的转换,如int和byte之间的转换。 而且,在Java的自动装箱和拆箱中,Integer也扮演着很重要的角色。在Java中,基本型和其对应的包装之间可以自动互相转换。例如,int型的数值可以直接赋值给Integer型的变量,这就是自动装箱;而将Integer型的对象赋值给int型的变量,就是自动拆箱。 总之,IntegerJava中非常重要的一个,涉及了Java的基本数据型转换、字符串转换等很多方面,也是面试中常见的问题,掌握好Integer的用法对Java开发来说非常重要。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值