kuky_xs

Results 44 comments of kuky_xs

TCP 提供一种面向连接的、可靠的字节流服务。其中,面向连接意味着两个使用 TCP 的应用(通常是一个客户和一个服务器)在彼此交换数据之前必须先建立一个 TCP 连接。在一个 TCP 连接中,仅有两方进行彼此通信;而字节流服务意味着两个应用程序通过 TCP 链接交换 8 bit 字节构成的字节流,TCP 不在字节流中插入记录标识符。 对于可靠性,TCP通过以下方式进行保证: - 数据包校验:目的是检测数据在传输过程中的任何变化,若校验出包有错,则丢弃报文段并且不给出响应,这时TCP发送数据端超时后会重发数据; - 对失序数据包重排序:既然TCP报文段作为IP数据报来传输,而IP数据报的到达可能会失序,因此TCP报文段的到达也可能会失序。TCP将对失序数据进行重新排序,然后才交给应用层; - 丢弃重复数据:对于重复数据,能够丢弃重复数据; - 应答机制:当TCP收到发自TCP连接另一端的数据,它将发送一个确认。这个确认不是立即发送,通常将推迟几分之一秒; - 超时重发:当TCP发出一个段后,它启动一个定时器,等待目的端确认收到这个报文段。如果不能及时收到一个确认,将重发这个报文段; - 流量控制:TCP连接的每一方都有固定大小的缓冲空间。TCP的接收端只允许另一端发送接收端缓冲区所能接纳的数据,这可以防止较快主机致使较慢主机的缓冲区溢出,这就是流量控制。TCP使用的流量控制协议是可变大小的滑动窗口协议。

ArrayList 和Vector都是使用数组方式存储数据,此数组元素数大于实际存储的数据以便增加和插入元素,它们都允许直接按序号索引元素,但是插入元素要涉及数组元素移动等内存操作,所以索引数据快而插入数据慢,Vector中的方法由于添加了synchronized修饰,因此Vector是线程安全的容器,但性能上较ArrayList差,因此已经是Java中的遗留容器。LinkedList使用双向链表实现存储(将内存中零散的内存单元通过附加的引用关联起来,形成一个可以按序号索引的线性结构,这种链式存储方式与数组的连续存储方式相比,内存的利用率更高),按序号索引数据需要进行前向或后向遍历,但是插入数据时只需要记录本项的前后项即可,所以插入速度较快。Vector属于遗留容器(Java早期的版本中提供的容器,除此之外,Hashtable、Dictionary、BitSet、Stack、Properties都是遗留容器),已经不推荐使用,但是由于ArrayList和LinkedListed都是非线程安全的,如果遇到多个线程操作同一个容器的场景,则可以通过工具类Collections中的synchronizedList方法将其转换成线程安全的容器后再使用(这是对装潢模式的应用,将已有对象传入另一个类的构造器中创建新的对象来增强实现)。

多继承虽然能使子类同时拥有多个父类的特征,但是其缺点也是很显著的,主要有两方面: (1)如果在一个子类继承的多个父类中拥有相同名字的实例变量,子类在引用该变量时将产生歧义,无法判断应该使用哪个父类的变量 (2)如果在一个子类继承的多个父类中拥有相同方法,子类中有没有覆盖该方法,那么调用该方法时将产生歧义,无法判断应该调用哪个父类的方法 正因为有以上的致命缺点,所以java中禁止一个类继承多个父类。 参考文档: 1)chrome-extension://cdonnmffkdaoajfknoeeecmchibpmkmg/static/pdf/web/viewer.html?file=https%3A%2F%2Fwww.cs.dartmouth.edu%2F~mckeeman%2Fcs118%2Freferences%2FOriginalJavaWhitepaper.pdf 2)https://www.zhihu.com/question/24317891 3)https://www.breakyizhan.com/java/4226.html

SharedPreferences 中不要存放大的键值对,因为会占用太多内存、引起 UI 卡顿及内存抖动等问题。在进行 SharedPreferences 数据持久时应该对持久化数据进行分类多 SharedPreferences 文件存储(譬如同一功能相关的放一个文件,或者按照读写频率及大小进行文件拆分),因为文件越大读取越慢,所以分类存储相对会好很多。对于频繁修改尽量做到批量一次性提交,尽量不要多次 edit 和 commit 或者 apply。不要直接用其进行跨进程读写操作,因为 SharedPreferences 不是进程安全的(MODE_MULTI_PROCESS 标记只是保证了在 API 11 以后如果内存中已经存在该 SharedPreference 则重性读一次文件到内存而已),如果要进行跨进程读写保证进程并发安全则建议使用 ContentProvider 对 SharedPreferences 进行包装或者采用其他 AIDL 等方式存储实现

1. 线程池作用就是限制系统中执行线程的数量。根据系统的环境情况,可以自动或手动设置线程数量,达到运行的最佳效果;少了浪费了系统资源,多了造成系统拥挤效率不高。用线程池控制线程数量,其他线程排队等候。一个任务执行完毕,再从队列的中取最前面的任务开始执行。若队列中没有等待进程,线程池的这一资源处于等待。当一个新任务需要运行时,如果线程池中有等待的工作线程,就可以开始运行了;否则进入等待队列。使用线程池的目的:一、减少了创建和销毁线程的次数,每个工作线程都可以被重复利用,可执行多个任务。二、可以根据系统的承受能力,调整线程池中工作线线程的数目,防止因为消耗过多的内存,而把服务器累趴下(每个线程需要大约1MB内存,线程开的越多,消耗的内存也就越大,最后死机)。 2. 几个重要的类: | Class | Expalin | | --------------------------- | :----------------------------------------------------------: | | ExecutorService | 真正的线程池接口。 | | ScheduledExecutorService | 能和Timer/TimerTask类似,解决那些需要任务重复执行的问题。 | | ThreadPoolExecutor | ExecutorService的默认实现。 | |...

静态变量是被static修饰符修饰的变量,也称为类变量,它属于类,不属于类的任何一个对象,一个类不管创建多少个对象,静态变量在内存中有且仅有一个拷贝; 实例变量必须依存于某一实例,需要先创建对象然后通过对象才能访问到它。静态变量可以实现让多个对象共享内存。

1. 在java中"=="是用来比较变量值是否相等。如果是基本类型,直接比较值。如果是对象类型,比较的是两个对象的引用,也就是地址。对象是放在堆中的,栈中存放的是对象的引用。"==" 是对栈中的值进行比较的。 2. Object里有一个方法“equals”,这个方法是用来比较两个对象是否相等的。在Object类中有这样的代码: ```java public boolean equals(Object o) { return this == o; } ``` 3. 在Object里提供了hashcode这个方法。要说hashcode就得说java集合。java有的集合是不能重复的,所以需要用equeals判断集合中元素是否是同一个。但是如果集合中现在已经有1000个元素,那么第1001个元素加入集合时,它就要调用1000次equals方法。这显然会大大降低效率。于是,Java采用了哈希表的原理。哈希(Hash)实际上是个人名,由于他提出一哈希算法的概念,所以就以他的名字命名了。哈希算法也称为散列算法,是将数据依特定算法直接指定到一个地址上。可以说hashCode方法实际上返回的就是对象存储的物理地址(实际可能并不是)。这样一来,当集合要添加新的元素时,先调用这个元素的hashCode方法,就一下子能定位到它应该放置的物理位置上。如果这个位置上没有元素,它就可以直接存储在这个位置上,不用再进行任何比较了;如果这个位置上已经有元素了,就调用它的equals方法与新元素进行比较,相同的话就不存了,不相同就散列其它的地址。 4. "=="与"equals"关系:如果类没有重写equals,那么对于该类的对象来说“==”和“equals”没有区别。都是比较对象的内存地址。 但在一些类库当中这个方法被覆盖掉了,如String,Integer,Date在这些类当中equals有其自身的实现,而不再是比较类在堆内存中的存放地址了。(特别注意String类) ##### 总结: 1. 如果两个对象相同,那么它们的hashCode值一定要相同; 2. 如果两个对象的hashCode相同,它们并不一定相同 ,上面说的对象相同指的是用eqauls方法比较。反过来:hashcode()不等,一定能推出equals()也不等;hashcode()相等,equals()可能相等,也可能不等。 如果重写这两个方法最好遵循以上原则。所以比较两者还要看具体是如何重写的。

1. 为什么 main 方法是静态的(static) 正因为 main 方法是静态的,JVM 调用这个方法就不需要创建任何包含这个 main 方法的实例。 因为 C 和 C++ 同样有类似的 main 方法作为程序执行的入口。 如果 main 方法不声明为静态的,JVM 就必须创建 main 类的实例,因为构造器可以被重载,JVM 就没法确定调用哪个 main 方法。 静态方法和静态数据加载到内存就可以直接调用而不需要像实例方法一样创建实例后才能调用,如果 main 方法是静态的,那么它就会被加载到 JVM...

方法的重载和重写都是实现多态的方式,区别在于前者实现的是编译时的多态性,而后者实现的是运行时的多态 性。 重载发生在一个类中,同名的方法如果有不同的参数列表(参数类型不同、参数个数不同或者二者都不同)则视为 重载;重写发生在子类与父类之间,重写要求子类被重写方法与父类被重写方法有相同的返回类型,比父类被重写方 法更好访问,不能比父类被重写方法声明更多的异常(里氏代换原则)。重载对返回类型没有特殊的要求。 方法重载的规则: 1. 方法名一致,参数列表中参数的顺序,类型,个数不同。 2. 重载与方法的返回值无关,存在于父类和子类,同类中。 3. 可以抛出不同的异常,可以有不同修饰符。 方法重写的规则: 1. 参数列表必须完全与被重写方法的一致,返回类型必须完全与被重写方法的返回类型一致。 2. 构造方法不能被重写,声明为 final 的方法不能被重写,声明为 static 的方法不能被重写,但是能够被再次 声明。 3. 访问权限不能比父类中被重写的方法的访问权限更低。 4. 重写的方法能够抛出任何非强制异常(UncheckedException,也叫非运行时异常),无论被重写的方法是否抛出异常。但是,重写的方法不能抛出新的强制性异常,或者比被重写方法声明的更广泛的强制性异常,反之则 可以。

进程:进程是具有独立功能的程序关于某个数据集合上的一次运行活动,是系统进行资源分配和调度(若不支持线程机制,进程的系统调度的单位。否则,线程是系统调度的单位)的独立单位。特点:一、进程是程序的一次执行过程。若程序执行两次甚至多次,则需要两个甚至多个进程。二、进程是是正在运行程序的抽象。它代表运行的CPU,也称进程是对CPU的抽象。三、系统资源(如内存、文件)以进程为单位分配。四、操作系统为每个进程分配了独立的地址空间。五、操作系统通过“调度”把控制权交给进程。进程的弊端:一、进程切换的代价、开销比较大。二、在一个进程内也需要并行执行多个程序,实现不同的功能。三、进程有时候性能比较低。(线程的引入为了解决进程的弊端)。 线程:一、有标识符ID。二、有状态及状态转换,所以需要提供一些状态转换操作。三、不运行时需要保存上下文环境,所以需要程序计数器等寄存器。四、有自己的栈和栈指针。五、共享所在进程的地址空间和其它资源。 总结:一、进程是程序在某个数据集合上的一次运行活动;线程是进程中的一个执行路径。(进程可以创建多个线程)。二、在支持线程机制的系统中,进程是系统资源分配的单位,线程是CPU调度的单位。三、进程之间不能共享资源,而线程共享所在进程的地址空间和其它资源。同时线程还有自己的栈和栈指针,程序计数器等寄存器。四、进程有自己独立的地址空间,而线程没有,线程必须依赖于进程而存在。五、进程切换的开销较大。线程相对较小。(前面也提到过,引入线程也出于了开销的考虑)。