==比较:
实际上比较的是地址值,因为在编译String s1="song"的时候,其实在jvm常量池中创建了一个内容为song的地址值,然后让s1去指向song,而不是把song直接赋值给s1
然后在执行String s2=new String(“song”)的视乎,要记住每new一次就会出现一个新的对象。所以这种情况是直接在堆内存中开辟了新的空间,存储的是在常量池中的song,所以堆内存中其实也是存储的是song的地址
==指的是引用的地址值是否相同,equals指的是引用的值是否相同,如果对象中没有重写equals方法,那么他们的也是比较的是引用的地址值是否相同。
两个对象的hashCode()相同,equals()不一定为true;两个对象的equals为true,则两个对象的hashcode一定为true;
hashCode的存在主要是用于查找的快捷,比如我们常用的HashMap等集合,hashCode用来在散列的存储结构中确定对象的存储地址。
java中所有的对象都有一个父类Object,而Object有一个hashCode方法,Java的所有类都有hashcode方法。
我们来看看hashcode的计算方法:
for (Object element : a) result = 31 * result + (element == null ? 0 : element.hashCode());
hashcode其实就是对一个对象中的每个元素进行一次运算生成的结果值,两个不同的对象是有可能出现同一个hash值。
比如:
String s1="Ma"; String s2="NB"; System.out.println(s1.hashCode()==s2.hashCode()); //true System.out.println(s1.equals(s2)); //false
虽然两个Ma和NB两个字符串不同,但是他们有相同的hashcode值2484。
创建实体类的时候如果要使用hashCode方法或equals方法时需要在实体类中重写:
@Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; User user = (User) o; return Objects.equals(name, user.name) && Objects.equals(age, user.age); } @Override public int hashCode() { return Objects.hash(name, age); }
同理,实体对象同样存在两个不同对象存在同一个hash值的情况。
在java中final中可以修饰类、变量、方法
①修饰成员变量时:修饰成员变量时必须显示初始化,初始化方式有两种,第一就是变量声名时直接初始化,二就是变量声明后不初始化,但必须要在这个变量所在的类的所有构造函数中对这个变量进行赋值。
②修饰局部变量时:当函数的参数通过final进行定义时,代表着该参数为只读,可以读取使用该参数,但不能修改该参数值。
Override 特点
从字面上看,重写就是 重新写一遍的意思。其实就是在子类中把父类本身有的方法重新写一遍。子类继承了父类原有的方法,但有时子类并不想原封不动的继承父类中的某个方法,所以在方法名,参数列表,返回类型(除过子类中方法的返回值是父类中方法返回值的子类时)都相同的情况下, 对方法体进行修改或重写,这就是重写。但要注意子类函数的访问修饰权限不能少于父类的。
Overload 特点
答:方法的重载和重写都是实现多态的方式,区别在于前者实现的是编译时的多态性,而后者实现的是运行时的多态性。重载发生在一个类中,同名的方法如果有不同的参数列表(参数类型不同、参数个数不同或者二者都不同)则视为重载;重写发生在子类与父类之间,重写要求子类被重写方法与父类被重写方法有相同的参数列表,有兼容的返回类型,比父类被重写方法更好访问,不能比父类被重写方法声明更多的异常(里氏代换原则)。重载对返回类型没有特殊的要求,不能根据返回类型进行区分。
math的round方法是四舍五入,如果参数是负数,则往大的数如-1.5等于-1。
引用数据类型,String并不是基本数据类,而是一个类class,是c++,java等语言编程中的字符串
1、字符类型: char 2、基本整型:byte,short,int,long 3、浮点型:float,double 4 布尔类型:boolean
String : final修饰,String类的方法都是返回new String。即对String对象的任何改变都不影响到原对象,对字符串的修改操作都会生成新的对象。
public StringBuffer() { super(16); }
String str = “i”代表着声明了一个变量str,此时在常量池中创建了一个内容为i的字符串对象。
String str = new String(“I”);此时代表着创建了两个对象,str引用地址指向堆内存,如果常量池中没有字符窜i,则会
在常量池中创建第二个对象字符串i。
public static String reverse(String str) { return new StringBuilder(str).reverse().toString(); }
//自定义方法 public static String reverse(String str){ char[] chars = str.toCharArray(); //创建StringBuilder对象进行拼接 StringBuilder builder = new StringBuilder(); for (int i = chars.length - 1; i >= 0; i--) { builder.append(chars[i]); } return builder.toString(); }
public static String reverse1(String str){ //创建StringBuilder对象进行拼接 StringBuilder builder = new StringBuilder(); //获取字符窜长度 int length = str.length(); for (int i = length-1; i >=0; i--) { builder.append(str.charAt(i)); } return builder.toString(); }
public static String reverse2(String str){ //获取字符窜长度 int length = str.length(); if(length<=1){ return str; } String left = str.substring(0, length/2); String right = str.substring(length/2,length); return reverse2(right)+reverse2(left); }
1.最普通的用法 String str1 = "aa,bb"; String[] split1 = str1.split(","); System.out.println(split1.length); //这个结果是2,都知道的 2.比较普通的用法 String str2 = ""; String[] split2 = str2.split(","); System.out.println(split2.length); //这个结果是1,但部分人会认为这个的结果是0, //这个为什么是1,我会在后面说 3.看起来比较奇怪的用法 String str3 = ","; String[] split3 = str3.split(","); System.out.println(split3.length); //这个结果是0,但部分人会认为结果是1,部分人会认为结果是2. //这个又为什么是0,我也会在后面说
抽象类可以没有抽象方法,但是如果你的一个类已经声明成了抽象类,即使这个类中没有抽象方法,它也不能再实例化,即不能直接构造一个该类的对象。 如果一个类中有了一个抽象方法,那么这个类必须声明为抽象类,否则编译通不过。
抽象类不能被实例化
抽象类可以有抽象方法,抽象方法只需申明,无需实现
含有抽象方法的类必须申明为抽象类
抽象类的子类必须实现抽象类中所有抽象方法,否则这个子类也是抽象类
抽象方法不能被声明为静态 :抽象方法是没有方法体的,也就是不具体实现什么,如果是静态的意味着可以直接调用,然而这样是没有什么意义的。
抽象方法不能用 private 修饰
抽象方法不能用 final 修饰
不能,抽象类是被用于继承的,final修饰代表不可修改、不可继承的。
1、抽象类和接口都不能直接实例化,如果要实例化,抽象类变量必须指向实现所有抽象方法的子类对象,接口变量必须指向实现所有接口方法的类对象。
2、抽象类要被子类继承,接口要被类实现。
3、接口只能做方法申明,抽象类中可以做方法申明,也可以做方法实现
4、接口里定义的变量只能是公共的静态的常量,抽象类中的变量是普通变量。:接口只是对一类事物的属性和行为更高层次的抽象。对修改关闭,对扩展(不同的实现implements)开放,接口是对开闭原则的一种体现。静态常量是不可以改变的,所以在接口中要是想要定义变量必须是静态常量
5、抽象类里的抽象方法必须全部被子类所实现,如果子类不能全部实现父类抽象方法,那么该子类只能是抽象类。同样,一个实现接口的时候,如不能全部实现接口方法,那么该类也只能为抽象类。
6、抽象方法只能申明,不能实现,接口是设计的结果 ,抽象类是重构的结果
7、抽象类里可以没有抽象方法
8、如果一个类里有抽象方法,那么这个类只能是抽象类
9、抽象方法要被实现,所以不能是静态的,也不能是私有的。
10、接口可继承接口,并可多继承接口,但类只能单继承。
接口和抽象的区别
Java中的流分为两种,一种是字节流,另一种是字符流,分别由四个抽象类来表示(每种流包括输入和输出两种所以一共四个):InputStream,OutputStream,Reader,Writer。Java中其他多种多样变化的流均是由它们派生出来的。
BIO是一个连接一个线程。 NIO是一个请求一个线程。 AIO是一个有效请求一个线程。
BIO:同步并阻塞,服务器实现模式为一个连接一个线程,即客户端有连接请求时服务器端就需要启动一个线程进行处理,如果这个连接不做任何事情会造成不必要的线程开销,当然可以通过线程池机制改善。
NIO:同步非阻塞,服务器实现模式为一个请求一个线程,即客户端发送的连接请求都会注册到多路复用器上,多路复用器轮询到连接有I/O请求时才启动一个线程进行处理。
AIO:异步非阻塞,服务器实现模式为一个有效请求一个线程,客户端的I/O请求都是由OS先完成了再通知服务器应用去启动线程进行处理。