Java基础语法
int类型溢出问题
判断int类型溢出,最简单的办法是用long类型
long temp;
if(temp > Integer.MAX_VALUE || temp < Integer.Min_VALUE)
return -1;
如果不用long类型,用int类型也可以判断
nos为temp的最后一位数,与Integer.MAX_VALUE和Integer.MIN_VALUE的最后一位数比较
int temp;
if(temp > Integer.MAX_VALUE / 10 || temp == Integer.MAX_VALUE / 10 && nos > 7)
return -1;
if(temp < Integer.MIN_VALUE / 10 || temp == Integer.MIN_VALUE / 10 && nos < -8)
return -1;
面向对象高级
继承
super关键字,子类继承父类时,在子类中使用,有以下三个主要的目的:
- 访问父类的构造方法
- 访问父类的属性
- 访问父类的方法
用super访问父类的构造方法时,一定要写在第一行,对象没有完成构造时,属性和方法自然也没办法进行访问
方法重写和重载的区别
重写(Override):
- 参数列表必须完全与父类一致
- 返回值类型必须与父类一致
- 访问权限不能比父类更低
- 父类的方法只能被其子类重写
- static和private方法不能重写
重载(Overload):
- 参数列表必须不同
- 返回值类型可以一样
- 访问权限无关
final关键字,可以修饰变量、类和方法
- 修饰变量时,如果修饰局部变量,可以先声明再赋值,但是只可以赋值一次;如果修饰成员变量,则必须在声明时赋值
- 修饰类时,不可以被继承
- 修饰方法时,不可以被子类重写
匿名内部类和局部内部类为什么只可以访问final修饰的变量?
首先,匿名内部类是局部内部类的一种,在编译时,JVM会把局部内部类的字节码单独编译成一段代码块,如果局部内部类可以访问变量,在变量修改的时候,局部内部类保留的值仍然是之前的旧值,为了避免出现这种逻辑问题,局部内部类只可以访问常量,也就是final修饰的变量
抽象
抽象类的现实意义是,一个父类可能被很多子类继承,但是该父类里的某个方法并不可以很好的代表每个子类的特点,因此将其抽象,交由每一个子类自行继承重写,因此子类必须重写父类的抽象方法,如果有抽象方法没重写,则子类也必须定义为抽象类
抽象类,抽象方法不可以被final和private修饰,因为没有意义,抽象类必须可以被继承
抽象类不能用new创建对象,但是抽象类可以有构造方法,在子类创建对象时,JVM也会调用抽象类的构造方法进行创建
接口
接口和抽象类的区别
- 抽象类要被子类继承,接口要被类实现
- 接口只能声明抽象方法,抽象类中可以声明抽象方法,也可以写非抽象方法
- 接口里定义的变量只能是公共的静态的常量,抽象类中的变量是普通变量
- 抽象类使用继承来使用, 无法多继承。 接口使用实现来使用, 可以多实现
- 抽象类中可以包含static方法 ,但是接口中不允许(静态方法不能被子类重写,因此接口中不能声明 静态方法)
- 接口不能有构造方法,但是抽象类可以有
多态
多态:对象的多种表现形态
方法的重写和重载也属于多态
向上转型:
Student a = new Student();
Person p = a;
p.say();
将学生a转型为人p,因为学生类是人类的子类,没有任何问题
向下转型:
Student a = new Student();
Person p = a;
Student b = (Student)p;
人类比学生类范围要大,向下转型时需要强制类型转换
多态的一个经典应用:
Student a = new Student();
Nurse n = new Nurese();
public static void say(Person s){
}
假如有一个方法say,定义的传参类型是抽象父类s,这时候不论是传入学生对象a还是护士对象n都可以正常执行该方法,并且对学生类和护士类的改动不会影响该方法本身
需要注意的是,向上转型会让该对象无法调用子类的扩展方法,如果子类有父类的重写方法,该对象调用时会调用到子类的重写方法,这种情况叫做动态绑定,如果一定要调用子类的扩展方法,则必须进行向下转型
instanceof关键字,用于判断到底是哪一种子类,还是以上述代码举例
if(s instanceof Student){
}else{
}
如此便可以判断传入的子类是不是Student类,使用该关键字返回的是boolean类型的值
这里还要注意,instanceof本质上是判断一个类是不是另一个类的实例化或者其子类的实例化,并不仅仅包含其本身
toString方法
toString方法,继承自object类的方法,在自己设计的类里重写此方法可以更好表达类的特点
equals方法
equals方法的必要性,==只比较内存地址是否相同,而无法比较某两个不同的对象成员变量的值是否相同,在对象之间的比较没法实现需要的效果。重写equals方法可以根据自己的需求进行指定属性的比较
重写equals方法的要求:
1、自反性:对于任何非空引用x,x.equals(x)应该返回true
2、对称性:对于任何引用x和y,如果x.equals(y)返回true,那么y.equals(x)也应该返回true
3、传递性:对于任何引用x、y和z,如果x.equals(y)返回true,y.equals(z)返回true,那么x.equals(z)也应该返回true
4、一致性:如果x和y引用的对象没有发生变化,那么反复调用x.equals(y)应该返回同样的结果。
5、非空性:对于任意非空引用x,x.equals(null)应该返回false
内部类
成员内部类
成员内部类可以无条件访问外部类的所有成员属性和成员方法(包括private成员和静态成员)。 不过要注意的是,当成员内部类拥有和外部类同名的成员变量或者方法时,会发生隐藏现象,即默认情况下访问的是成员内部类的成员。如果要访问外部类的同名成员,需要以下面的形式进行访问:
- 外部类.this.成员变量
- 外部类.this.成员方法
局部内部类
局部内部类的主要作用是,某个方法可能传入了一个还没有被实现的接口,而为了这个接口去创建一个新的类会显得很浪费,因为这个方法或许只用一次,因此可以在调用这个方法的时候创建一个局部内部类去实现这个接口,以便进行该方法的调用
匿名内部类
创建格式 new 父类构造器(参数列表)| 实现接口() { //匿名内部类的类体部分 }
- 使用匿名内部类时,我们必须是继承一个类或者实现一个接口,但是两者不可兼得,同时也只能 继承一个类或者实现一个接口
- 匿名内部类中是不能定义构造函数的
- 匿名内部类中不能存在任何的静态成员变量和静态方法
- 匿名内部类为局部内部类,所以局部内部类的所有限制同样对匿名内部类生效
- 匿名内部类不能是抽象的,它必须要实现继承的类或者实现的接口的所有抽象方法
- 只能访问final型的局部变量
静态内部类
静态内部类参考main方法,静态内部类不可以访问外部类的非静态方法和变量
注意事项
内部类在编译时是单独生成一个字节码文件,因此里面一旦访问了内部类以外的变量,该变量必须为final,否则会出现变量的数值不匹配的问题
包装类
包装类是基本数据类型的对象实现
Number:Integer、Short、Long、Double、Float、Byte都是Number的子类表示是一个数字
Object:Character、Boolean都是Object的直接子类
因此八大包装类被分为两个大类
自动装箱和自动拆箱
Integer i = 10;
int a = i;
包装类的作用(待补充)
首先,包装类里提供了非常实用的方法,比如Integer类里的
parseInt(String s) 将字符串s转换成十进制整数
其次,在一些核心类里,比如LinkedList,在创建的时候必须传入包装类
LinkedList<Integer> data = new LinkedList();
如果传入基本类会报错
可变参数
语法: 返回值类型 方法名称(数据类型…参数名称){
//参数在方法内部 , 以数组的形式来接收
}
注意: 可变参数只能出现在参数列表的最后