java:

java中jvm,jre,jdk的联系与区别:

java bin文件夹里没有javac java文件必须在bin目录下吗_java

jdk(Java SE Development Kit):

java标准开发包,提供了编译、运行java程序所需的各种工具和资源,包括java编译器、java运行环境,以及常用的java类库。

下图是jdk安装目录:

java bin文件夹里没有javac java文件必须在bin目录下吗_jvm_02

JRE

jre、java运行环境,用于解释执行java的字节码文件。普通用户只需要安装jre来运行java程序,程序开发者必须安装jdk来编译、调试程序。下图是JRE的安装目录:里面有两个文件夹bin和lib,在这里可以认为bin里的就是jvm,lib中则是jvm工作所需要的类库,而jvm和 lib和起来就称为jre。

java bin文件夹里没有javac java文件必须在bin目录下吗_android_03

JVM

jvm,java虚拟机,是jre的一部分。它是整个java实现跨平台最核心的部分,负责解释执行字节码文件,是可运行java字节码文件的虚拟计算机。所有平台上的jvm向编译器提供相同接口,而编译器只需要面向虚拟机,生成虚拟机能识别的代码,由虚拟机解释执行。当使用Java编译器编译Java程序时,生成的是与平台无关的字节码,这些字节码只面向JVM。不同平台的JVM都是不同的,但它们都提供了相同的接口。JVM是Java程序跨平台的关键部分,只要为不同平台实现了相应的虚拟机,编译后的Java字节码就可以在该平台上运行。

java面向对象的特征:

java面向对象三大特征是封装、继承和多态。
封装是保证软件部件具有优良的模块性的基础,封装的目标就是要实现软件部件的“高内聚、低耦合”,防止程序相互依赖性而带来的 变动影响。在面向对象的编程语言中,对象是封装的最基本单位,面向对象的封装比传统语言的封装更为清晰、更为有力。面向对象的封装就 是把描述一个对象的属性和行为的代码封装在一个类中。
继承是在定义和实现一个类的时候,可以在一个已经存在的类的基础之上来进行,把这个已经存在的类所定义的内容作为自己的内容,并可以加入 若干新的内容,或修改原来的方法使之更适合特殊的需要,这就是继承。继承是子类自动共享父类数据和方法的机制,这是类之间的一种关 系,提高了软件的可重用性和可扩展性
多态是指程序中定义的引用变量所指向的具体类型和通过该引用变量发出的方法调用在编程时并不确定,而是在程序运行期间才确定,即 一个引用变量倒底会指向哪个类的实例对象,该引用变量发出的方法调用到底是哪个类中实现的方法,必须在由程序运行期间才能决定。 因为在程序运行时才确定具体的类,这样,不用修改源程序代码,就可以让引用变量绑定到各种不同的类实现上,从而导致该引用调用的 具体方法随之改变,即不修改程序代码就可以改变程序运行时所绑定的具体代码,让程序可以选择多个运行状态,这就是多态性。多态性 增强了软件的灵活性和扩展性。
多态的实现:
继承在为多态的实现做了准备。子类Child继承父类Father,我们可以编写一个指向子类的父类类型引用,该引用既 可以处理父类Father对象,也可以处理子类Child对象,当相同的消息发送给子类或者父类对象时,该对象就会根据自己所属的引用而执行 不同的行为,这就是多态。即多态性就是相同的消息使得不同的类做出不同的响。
Java实现多态有三个必要条件:继承、重写、向上转型。
继承:在多态中必须存在有继承关系的子类和父类。 重写:子类对父类中某些方法进行重新定义,在调用这些方法时就会调用子类的方法。 向上转型:在多态中需要将子类的引用赋给父类对象,只有这样该引用才能够调用父类的方法和子类的方法。
实现形式:继承和接口
基于继承的实现机制主要表现在父类和继承该父类的一个或多个子类对某些方法的重写,多个子类对同一方法的重写可以表现出不同的行为。 继承都是单继承,只能为一组相关的类提供一致的服务接口。但是接口可以是多继承多实现,它能够利用一组相关或者不相关的接口进行组合与扩充, 能够对外提供一致的服务接口。所以它相对于继承来说有更好的灵活性。
抽象:
抽象就是找出一些事物的相似和共性之处,然后将这些事物归为一个类,这个类只考虑这些事物的相似和共性之处,并且会忽略与当前主 题和目标无关的那些方面,将注意力集中在与当前目标有关的方面。例如,看到一只蚂蚁和大象,你能够想象出它们的相同之处,那就是抽 象。抽象包括行为抽象和状态抽象两个方面。例如,定义一个Person类,定义他们的共有的一些属性,name\age\sex等等

抽象类和接口区别:

1.默认的实现方法:

(1)抽象类可以有默认的方法实现是完全抽象的。

抽象类中可以有已经实现了的方法,也可以有被abstract修饰的方法(抽象方法),因为存在抽象方法,所以该类必须是抽象类。

(2)接口根本不存在方法的实现。

但是接口要求只能包含抽象方法,抽象方法是指没有实现的方法。接口就根本不能存在方法的实现。

2子类使用的关键词不一样

(1)实现抽象类使用extends关键字来继承抽象类。如果子类不是抽象类的话,它需要提供抽象类中所有声明的方法的实现。

抽象类虽然不能实例化来使用,但是可以被继承,让子类来具体实现父类的所有抽象方法。但是如果子类将抽象方法没有全部实现,就必须把自己也修饰成抽象类,交于继承它的子类来完成实现。以此类推,直到没有抽象函数。

(2)子类使用关键字implements来实现接口。它需要提供接口中所有声明的方法的实现。

接口的实现,通过implements关键字。实现该接口的类,必须把接口中的所有方法给实现。不能再推给下一代。(和抽象类相比,抽象类是将梦想传给家族,一代一代去完成。那么接口就是掌门人找大师兄来完成帮派的鸿星伟业,这时候就只有一次希望,要么有能力就实现,没能力就不要接。

3、是否有构造器

(1)抽象类可以有构造器

抽象类是属于类,享有类的所有特性(但是不能实例化),当然包括类的构造方法,也就是构造器。

2)接口不能有构造器

接口是所有抽象方法的集合,注意,是集合,不是类。当然没有构造方法一说,更别提什么构造器了。

4.可使用修饰符:

(1)抽象方法可以有public、protected和default这些修饰符

抽象类的目的就是被继承,抽象方法就是为了被重写,所以肯定不能用private修饰符,肯定是可以用public的。但是protected和default也是可以的。

(2)接口方法默认修饰符是public。你不可以使用其它修饰符。

接口就有且只有一个public修饰。

5.速度方面:

(1)抽象方法比接口速度要快

(2)接口是稍微有点慢的,因为它需要时间去寻找在类中实现的方法。

6.增加新方法对子类的影响:

(1)如果你往抽象类中添加新的方法,你可以给它提供默认的实现。因此你不需要改变你现在的代码。

抽象类可以有一些非抽象方法的存在,这些方法被称为默认实现。如果添加一个默认实现方法(不能是抽象方法),就不需要在子类中去实现,所以继承这个抽象类的子类无须改动。如果你往接口中添加方法,那么你必须改变实现该接口的类。

(2)接口中只能添加抽象方法,当你添加了抽象方法,实现该接口的类就必须实现这个新添加的方法。

因为,定义中说的很清楚,接口的实现必须实现所有的方法。所有,当然包括新添加的方法。

7.子类能继承的数量:

抽象类在java语言中所表示的是一种继承关系,一个子类只能存在一个父类,但是可以存在多个接口。

java在类的继承上并没有多继承。抽象类属于类,所以可以被继承。但子类只能继承一个父类。

java为了实现多继承,使用了接口。一个类可以实现多个接口。

静态属性和静态方法是否可以继承,被重写。

静态属性和静态方法可以被子类继承,但是静态属性不能被子类重写。
重写的本质是动态绑定,根据运行时的对象的类型来决定调用哪个方法,而不是根据编译时的类型。静态方法属于类的,再编译阶段已经静态绑定到类上,表现出来就是通过类名.方法名进行访问,所以无法被子类重写。

重写和重载:

重写:

重写是子类对父类的允许访问的方法的实现过程进行重新编写, 返回值和形参都不能改变。即外壳不变,核心重写!

重写的好处在于子类可以根据需要,定义特定于自己的行为。 也就是说子类能够根据需要实现父类的方法。

重写方法不能抛出新的检查异常或者比被重写方法申明更加宽泛的异常。例如: 父类的一个方法申明了一个检查异常 IOException,但是在重写这个方法的时候不能抛出 Exception 异常,因为 Exception 是 IOException 的父类,抛出 IOException 异常或者 IOException 的子类异常。

重写规则:

参数列表与被重写方法的参数列表必须完全相同。
返回类型与被重写方法的返回类型可以不相同,但是必须是父类返回值的派生类(java5 及更早版本返回类型要一样,java7 及更高版本可以不同)。
访问权限不能比父类中被重写的方法的访问权限更低。例如:如果父类的一个方法被声明为 public,那么在子类中重写该方法就不能声明为 protected。
父类的成员方法只能被它的子类重写。
声明为 final 的方法不能被重写。
声明为 static 的方法不能被重写,但是能够被再次声明。
子类和父类在同一个包中,那么子类可以重写父类所有方法,除了声明为 private 和 final 的方法。
子类和父类不在同一个包中,那么子类只能够重写父类的声明为 public 和 protected 的非 final 方法。
重写的方法能够抛出任何非强制异常,无论被重写的方法是否抛出异常。但是,重写的方法不能抛出新的强制性异常,或者比被重写方法声明的更广泛的强制性异常,反之则可以。
构造方法不能被重写。
如果不能继承一个类,则不能重写该类的方法。

重载

重载(overloading) 是在一个类里面,方法名字相同,而参数不同。返回类型可以相同也可以不同。
每个重载的方法(或者构造函数)都必须有一个独一无二的参数类型列表。最常用的地方就是构造器的重载。

方法的重写(Overriding)和重载(Overloading)是java多态性的不同表现,重写是父类与子类之间多态性的一种表现,重载可以理解成多态的具体表现形式。
(1)方法重载是一个类中定义了多个方法名相同,而他们的参数的数量不同或数量相同而类型和次序不同,则称为方法的重载(Overloading)。
(2)方法重写是在子类存在方法与父类的方法的名字相同,而且参数的个数与类型一样,返回值也一样的方法,就称为重写(Overriding)。
(3)方法重载是一个类的多态性表现,而方法重写是子类与父类的一种多态性表现。

Android:

Handler的消息机制及其原理

首先在UI线程我们创建了一个Handler实例对象,无论是匿名内部类还是自定义类生成的Handler实例对象,我们都需要对handleMessage方法进行重写,在handleMessage方法中我们可以通过参数msg来写接受消息过后UIi线程的逻辑处理,接着我们创建子线程,在子线程中需要更新UI的时候,新建一个Message对象,并且将消息的数据记录在这个消息对象Message的内部,比如arg1,arg2,obj等,然后通过前面的Handler实例对象调用sendMessge方法把这个Message实例对象发送出去,之后这个消息会被存放于MessageQueue中等待被处理,此时MessageQueue的管家Looper正在不停的把MessageQueue存在的消息取出来,通过回调dispatchMessage方法将消息传递给Handler的handleMessage方法,最终前面提到的消息会被Looper从MessageQueue中取出来传递给handleMessage方法,最终得到处理。这就是Handler机制整个的工作流程。
Handler的理解、用法以及运行机制

Handler中looper死循环为什么不导致应用卡死?

loop无限循环用于取出消息并将消息分发出去,没有消息时会阻塞在queue.next()里的nativePollOnce()方法里,并释放CPU资源进入休眠。Android的绝大部分操作都是通过Handler机制来完成的,如果没有消息,则不需要程序去响应,就不会有ANR。ANR一般是消息的处理过程中耗时太长导致没有及时响应用户操作。
Looper死循环为什么不会导致应用卡死Handler.postDelayed()的原理

http和https区别:

HTTPS和HTTP的区别主要如下:

1、https协议需要到ca申请证书,一般免费证书较少,因而需要一定费用。

2、http是超文本传输协议,信息是明文传输,https则是具有安全性的ssl加密传输协议。

3、http和https使用的是完全不同的连接方式,用的端口也不一样,前者是80,后者是443。

4、http的连接很简单,是无状态的;HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,比http协议安全。

算法:统计一个数字在排序数组中出现的次数

这是剑指offer里面的题目貌似。
因为是排序数组,而且这种题目肯定是有比扫描更好的方法的,比较好的方法时用二分查找出数字的其实位置和末尾位置,时间复杂度时O(logN)

class Solution {
public:
    int GetNumberOfK(vector<int> data ,int k) {
        int Size = data.size();
        if(Size==0) return 0;
        if(data[0]>k||data[Size-1]<k) return 0;
        int FirstK = GetFirstK(data,k);
        int LastK = GetLastK(data,k);
        if(FirstK!=-1&&LastK!=-1) return LastK-FirstK+1;
        else return 0;
    }
    int GetFirstK(vector<int> data, int k){
        int Size = data.size();
        int Left = 0, Right = Size-1, IndexK = -1;
        if(data[Left]==k) return Left;
        int Mid;
        while(Left<=Right){
            Mid = (Left+Right)/2;
            if(data[Mid]==k) {
                if(data[Mid-1]<k) return Mid;
                else Right = Mid-1;
            }
            else if(data[Mid]<k) Left = Mid+1;
            else Right = Mid-1;
            
        }
        return -1;
    }
    int GetLastK(vector<int> data, int k){
        int Size = data.size();
        int Left = 0, Right = Size-1, IndexK = -1;
        if(data[Right]==k) return Right;
        int Mid;
        while(Left<=Right){
            Mid = (Left+Right)/2;
            if(data[Mid]==k){
                if(data[Mid+1]>k) return Mid;
                else Left = Mid+1;
            }
            else if(data[Mid]>k) Right = Mid-1;
            else Left = Mid+1;
            }
        return -1;
    }
};