一 String、StringBuffer、StringBuilder
String 为什么要设计成不可变的?
String是不可变的(修改String时,不会在原有的内存地址修改,而是重新指向一个新对象),String用final修饰,不可继承,String本质上是个final的char[]数组,所以char[]数组的内存地址不会被修改,而且String 也没有对外暴露修改char[]数组的方法。不可变性可以保证线程安全以及字符串串常量池的实现。
三者在执行速度方面的比较:StringBuilder > StringBuffer > String
String每次变化一个值就会开辟一个新的内存空间
StringBuilder:线程非安全的
StringBuffer:线程安全的
对于三者使用的总结:
1.如果要操作少量的数据用 String。
2.单线程操作字符串缓冲区下操作大量数据用 StringBuilder。
3.多线程操作字符串缓冲区下操作大量数据用 StringBuffer。
String 是 Java 语言非常基础和重要的类,提供了构造和管理字符串的各种基本逻辑。它是典型的 Immutable 类,被声明成为 final class,所有属性也都是 final 的。也由于它的不可变性,类似拼接、裁剪字符串等动作,都会产生新的 String 对象。由于字符串操作的普遍性,所以相关操作的效率往往对应用性能有明显影响。
StringBuffer 是为解决上面提到拼接产生太多中间对象的问题而提供的一个类,我们可以用 append 或者 add 方法,把字符串添加到已有序列的末尾或者指定位置。StringBuffer 本质是一个线程安全的可修改字符序列,它保证了线程安全,也随之带来了额外的性能开销,所以除非有线程安全的需要,不然还是推荐使用它的后继者,也就是 StringBuilder。
StringBuilder 是 Java 1.5 中新增的,在能力上和 StringBuffer 没有本质区别,但是它去掉了线程安全的部分,有效减小了开销,是绝大部分情况下进行字符串拼接的首选。
二 异常处理
Java异常结构中定义有Throwable类。 Exception和Error为其子类。
Exception是程序本身可以处理的异常,这种异常分两大类:运行时异常和非运行时异常,程序中应当尽可能去处理这些异常。
运行时异常:都是RuntimeException类及其子类异常,如NullPointerException、IndexOutOfBoundsException等, 这些异常是不检查异常,程序中可以选择捕获处理,也可以不处理。这些异常一般是由程序逻辑错误引起的, 程序应该从逻辑角度尽可能避免这类异常的发生。
非运行时异常:是需要显示用try-catch捕捉处理的异常,如IOException等
Error是程序无法处理的错误,比如OutOfMemoryError、StackOverflowError。这些异常发生时, Java虚拟机(JVM)一般会选择线程终止。
Java语言异常处理
- 对代码块用try…catch进行异常捕获处理;
finally块没有处理异常的能力。处理异常的只能是catch块。
不管有没有异常,finally 中的代码都会执行
当 try、catch 中有 return 时,finally 中的代码依然会继续执行
2.在方法体外用throws进行抛出声明
public void foo() throws ExceptionType1 , ExceptionType2 ,ExceptionTypeN
{
//foo内部可以抛出 ExceptionType1 , ExceptionType2 ,ExceptionTypeN 类的异常,或者他们的子类的异常对象。
}
3.在代码块用throw手动抛出一个异常对象
public void save(User user)
{
if(user == null)
throw new IllegalArgumentException("User对象为空");
//......
}
异常处理的两个基本原则:
- 尽量不要捕获类似 Exception 这样的通用异常,而是应该捕获特定异常。
- 不要生吞异常。
三 Java 语言的三大特性:封装,继承,多态
什么是多态
多态是同一个行为具有多个不同表现形式或形态的能力。
多态就是同一个接口,使用不同的实例而执行不同操作
如图所示:
多态的必要条件:
1.子类继承父类并重写父类的方法。
2.父类的引用指向子类对象。
定义格式:父类类型 变量名=new 子类类型();
多态中成员的特点
1. 多态成员变量:编译运行看左边
Fu f=new Zi();
System.out.println(f.num);//f是Fu中的值,只能取到父中的值
2. 多态成员方法:编译看左边,运行看右边
Fu f1=new Zi();
System.out.println(f1.show());//f1的门面类型是Fu,但实际类型是Zi, 所以调用的是重写后的方法。
多态的好处:
1.可替换性:多态对已存在代码具有可替换性。例如,多态对圆Circle类工作,对其他任何圆形几何体,如圆环,也同样工作。
2.可扩充性:多态对代码具有可扩充性。增加新的子类不影响已存在类的多态性、继承性,以及其他特性的运行和操作。实际上新加子类更容易获得多态功能。
3.接口性:多态是超类通过方法签名,向子类提供了一个共同接口,由子类来完善或者覆盖它而实现的。
4.灵活性:它在应用中体现了灵活多样的操作,提高了使用效率。
5.简化性:多态简化对应用软件的代码编写和修改过程,尤其在处理大量对象的运算和操作时,这个特点尤为突出和重要。
多态的例子:
public class Test {
public static void main(String[] args) {
show(new Cat()); // 以 Cat 对象调用 show 方法
show(new Dog()); // 以 Dog 对象调用 show 方法
Animal a = new Cat(); // 向上转型
a.eat(); // 调用的是 Cat 的 eat
Cat c = (Cat)a; // 向下转型
c.work(); // 调用的是 Cat 的 work
}
public static void show(Animal a) {
a.eat();
// 类型判断
if (a instanceof Cat) { // 猫做的事情
Cat c = (Cat)a;
c.work();
} else if (a instanceof Dog) { // 狗做的事情
Dog c = (Dog)a;
c.work();
}
}
}
abstract class Animal {
abstract void eat();
}
class Cat extends Animal {
public void eat() {
System.out.println("吃鱼");
}
public void work() {
System.out.println("抓老鼠");
}
}
class Dog extends Animal {
public void eat() {
System.out.println("吃骨头");
}
public void work() {
System.out.println("看家");
}
}
多态的实现方式:
基本上是重载、接口、继承(重写) 可通过这三种方式实现多态
8、抽象和接口(重要)
抽象类的意义?
为其子类提供一个公共的类型,封装子类中的重复内容,定义抽象方法,子类虽然有不同的实现,但是定义是一致的。
接口的意义?
规范、扩展、回调。
共同点:
- 是上层的抽象层。
- 都不能被实例化。
- 都能包含抽象的方法,这些抽象的方法用于描述类具备的功能,但是不提供具体的实现。
区别:
在抽象类中可以写非抽象的方法,从而避免在子类中重复书写他们,这样可以提高代码的复用性,这是抽象类的优势,接口中只能有抽象的方法。
多继承:一个类只能继承一个直接父类,这个父类可以是具体的类也可是抽象类,但是一个类可以实现多个接口。
抽象类可以有默认的方法实现,接口根本不存在方法的实现。
子类使用extends关键字来继承抽象类。如果子类不是抽象类的话,它需要提供抽象类中所有声明方法的实现。子类使用关键字implements来实现接口。它需要提供接口中所有声明方法的实现。
构造器:抽象类可以有构造器,接口不能有构造器。
和普通Java类的区别:除了你不能实例化抽象类之外,抽象类和普通Java类没有任何区别,接口是完全不同的类型。
访问修饰符:抽象方法可以有public、protected和default修饰符,接口方法默认是public abstract**** 。你不可以使用其它修饰符。接口中的所有属性默认为:public static final ****.
main方法:抽象方法可以有main方法并且我们可以运行它,接口没有main方法,因此我们不能运行它。
速度:抽象类比接口速度要快,接口是稍微有点慢的,因为它需要时间去寻找在类中实现的方法。
添加新方法:如果你往抽象类中添加新的方法,你可以给它提供默认的实现。因此你不需要改变你现在的代码。如果你往接口中添加方法,那么你必须改变实现该接口的类。
8、内部类,匿名内部类
内部类
非静态内部类没法在外部类的静态方法中实例化。
非静态内部类的方法可以直接访问外部类的所有数据,包括私有的数据。
在静态内部类中调用外部类成员,成员也要求用 static 修饰。
创建静态内部类的对象可以直接通过外部类调用静态内部类的构造器;创建非静态的内部类的对象必须先创建外部类的对象,通过外部类的对象调用内部类的构造器。
匿名内部类
匿名内部类不能定义任何静态成员、方法
匿名内部类中的方法不能是抽象的
匿名内部类必须实现接口或抽象父类的所有抽象方法
匿名内部类不能定义构造器
匿名内部类访问的外部类成员变量或成员方法必须用 final 修饰