一文让你深入了解JavaSE的知识点(上)
https://developer.aliyun.com/article/1496444?spm=a2c6h.13148508.setting.14.7b724f0e6A8pon
2.二维数组
Java中的二维数组是由多个一维数组组成的数组。它可以被认为是一个表格,其中的每个元素都有两个索引,一个用于指定行号,另一个用于指定列号。他的一些注意事项和一维数组差不多除了
- 数组长度:二维数组的长度是指行数,可以使用
数组名.length
来获取二维数组的行数。要获取每一行的列数,可以使用数组名[行索引].length
。 - 不规则二维数组:Java中的二维数组可以是不规则的,即每一行的列数可以不同。在声明和初始化不规则二维数组时,需要为每一行指定具体的列数。
- 声明和初始化:要声明一个二维数组,需要指定数组的行数和列数
- 别的博主就不过多的赘述了
六.面向对象三巨头
ava是一门纯面向对象的语言(Object Oriented Program,简称OOP),面向对象是一种编程范式,它将程序的组织方式从过程化的思维方式转变为以对象为中心的思维方式。在面向对象编程中,程序被组织成一组相互协作的对象,每个对象都有自己的状态和行为,并且可以通过消息传递来进行交互。面向对象的编程语言提供了类和对象的概念,通过定义类来创建对象,并通过对象之间的交互来实现程序的功能,Java面向对象有三大巨头------封装,继承,多态 。下文博主将一一介绍它们的语法以及优点等等。
一.封装
1.什么是封装
封装是面向对象编程中的一个重要概念,指的是将抽象出来的数据和对数据的操作封装在一起,形成一个类(或对象),使其只能通过类(或对象)提供的接口来访问和操作数据,同时隐藏了数据的实现细节,从而达到保护数据的安全和完整性的目的。通过封装,程序员可以将复杂的系统简化并提高代码的可维护性和可扩展性。
2.为什么要封装
封装的目的是保护数据的安全和完整性,同时隐藏数据的实现细节,提高代码的可维护性和可扩展性,具体有以下几个方面的好处:
- 保护数据的安全和完整性:封装可以将数据隐藏起来,使得外部代码无法直接访问和修改数据,从而防止数据被意外修改或篡改,提高数据的安全性和可靠性。
- 隐藏实现细节:封装可以隐藏数据的实现细节,将复杂的实现逻辑封装到类的内部,对外部代码来说,只需要关心调用类的接口即可,不必关心类的内部实现,降低了代码的耦合度,提高了代码的可维护性和可读性。
- 提高代码的可维护性和可扩展性:封装可以将数据和操作进行分离,使得修改数据的实现细节并不会影响对外部接口的调用方式,从而提高了代码的可维护性和可扩展性,方便系统的后续维护和升级。
3.该如何实现封装
Java中主要通过类和访问权限来实现封装:类可以将数据以及封装数据的方法结合在一起,更符合人类对事物的认知,而访问权限用来控制方法或者字段能否直接在类外使用。Java中提供了四种访问限定符:
访问限定符
NO | 范围 | private | default(默认) | protected | public |
1 | 同一个包中的同一类 | ☑️ | ☑️ | ☑️ | ☑️ |
2 | 同一个包中的不同类 | ☑️ | ☑️ | ☑️ | |
3 | 不同包中的子类 | ☑️ | ☑️ | ||
4 | 不同包中的非子类 | ☑️ |
说明:访问限定符不仅可以限制成员属性的访问权限也可以限制类的访问权限;一般成员变量由private 所修饰 成员方法由 public所修饰;default :表示的是没有写访问限定符就默认为default所修饰
4.实例举例
public class Employee { private String name; // 将属性进行封装 private String department; // 将属性进行封装 private int age; // 将属性进行封装 public String getName() { return name; // 只暴露出了获取属性的接口 } public void setDepartment(String department) { this.department = department; // 只暴露出了设置属性的接口 } public void increaseAge() { age++; // 只暴露出了对属性进行修改的接口 } }
在这个例子中,将员工的姓名、部门和年龄进行了封装,只在外部暴露了获取姓名和设置部门、增加年龄的接口,从而保护了属性的安全和完整性,同时隐藏了实现细节。
5.说明
当然以上举得例子只是封装一个小小的优点之一,等和继承与多态结合起来一起使用,你就会发现封装的妙用了
二.继承
1.什么是继承
继承是面向对象编程中的一个概念,它指的是一个类可以派生出新的类,新的类可以继承原来类的属性和方法,同时可以在原有基础上增加自己的属性和方法,从而达到代码复用的目的。继承可以通过子类来扩展或者修改父类的功能,提高代码的可维护性和可复用性。在继承关系中,被继承的类被称为父类或基类,继承的类被称为子类或派生类。
2.为什么要继承呢
首先让我们看一下下面的例子
class Animal { public String name; public int age; public void eat() { System.out.println(this.name+"正在吃"); } } class Dog { public String name; public int age; public void eat() { System.out.println(this.name+"正在吃"); } public void Bark() { System.out.println(this.name+"汪汪叫"); } } class Bird { public String name; public int age; public void eat() { System.out.println(this.name+"正在吃"); } public void Bugu() { System.out.println(this.name+"布谷布谷叫"); } }
从以上代码可以看出我们设计出的了三个类,相信细心的读者们可以发现这三个类有很多共性的地方,代码有很多的重复使用了,而继承就是为了解决这个问题
3.继承的使用
上述图示中,Dog和Bird都继承了Animal类,其中:Animal类称为父类/基类或超类,Dog和Bird可以称为Animal的子类/派生类,继承之后,子类可以复用父类中成员,子类在实现时只需关心自己新增加的成员即可。
从继承概念中可以看出继承最大的作用就是:实现代码复用,还有就是来实现多态
4.继承的语法
在Java中如果要表示类之间的继承关系,需要借助extends关键字,具体如下
class Animal { public String name; public int age; public void eat() { System.out.println(this.name+"正在吃"); } } class Dog extends Animal { public void Bark() { System.out.println(this.name+"汪汪叫"); } } class Bird extends Animal { public void Bugu() { System.out.println(this.name+"布谷布谷叫"); } }
5.继承中的一些注意事项
1.Java只能单继承,不可以实现多继承
2.成员变量访问遵循就近原则,自己有优先自己的,如果没有则向父类中找。
3.子类要想访问父类中的成员属性可以使用关键字 super()来访问如下图
class Animal { public String name = "小黑"; public int age; public void eat() { System.out.println(this.name+"正在吃"); } } class Dog extends Animal { public String name = "旺财"; public void Bark() { System.out.println(this.name+"汪汪叫"); } public void func() { System.out.println(super.name); } } public class Main { public static void main(String[] args) { Dog dog = new Dog(); dog.func(); } }
结果如下
4.父子父子,先有父再有子,即:子类对象构造时,需要先调用基类构造方法,然后执行子类的构造方法。
class Animal { public String name; public int age; public Animal(String name, int age) { this.name = name; this.age = age; } public void eat() { System.out.println(this.name+"正在吃"); } } class Dog extends Animal { public Dog(String name, int age, String sex) { super(name, age); this.sex = sex; } public String sex; public void Bark() { System.out.println(this.name+"汪汪叫"); } public void func() { System.out.println(super.name); } }
因为:子类对象中成员是有两部分组成的,基类继承下来的以及子类新增加的部分 。父子父子肯定是先有父再有子,所以在构造子类对象时候 ,先要调用基类的构造方法,将从基类继承下来的成员构造完整,然后再调用子类自己的构造方法,将子类自己新增加的成员初始化完整 。
注意:
1. 若父类显式定义无参或者默认的构造方法,在子类构造方法第一行默认有隐含的super()调用,即调用基类构造方法
2. 如果父类构造方法是带有参数的,此时需要用户为子类显式定义构造方法,并在子类构造方法中选择合适的父类构造方法调用,否则编译失败。
3. 在子类构造方法中,super(...)调用父类构造时,必须是子类构造函数中第一条语句。
4. super(...)只能在子类构造方法中出现一次,并且不能和this同时出现
5. super和this
super和this是两个关键字,都是用来引用对象或类的,但是它们有不同的作用和用法。
this关键字用于在一个类的方法中引用该类的成员变量、方法或构造函数。通常用于区分成员变量和方法名相同的情况。例如:
public class Person{ private String name; public Person(String name){ this.name = name; } public String getName(){ return this.name; } }
在上述代码中,this.name引用了该类的成员变量name,而非方法中的参数name。
super关键字用于在子类中引用父类的成员变量、方法或构造函数。通常用于在子类中重写父类的方法时,调用父类的方法或调用父类的构造函数。例如:
public class Person{ private String name; public Person(String name){ this.name = name; } public String getName(){ return this.name; } }
在上述代码中,super(name)调用了父类Animal的构造函数,而super.eat()调用了父类Animal的eat方法。
6.封装在继承中的使用
1.private 即只能在自己类中被访问,父类中private成员变量虽然在子类中不能直接访问,但是也继承到子类中了
2.default 即默认在同一个包内父类的default成员变量子类可以访问
3.protected 即在同一个包或者不同包的父类成员变量被protected修饰的子类可以访问
4.public 即都可以被访问
7.final的使用
在继承中,final
关键字通常用于类、方法或属性上,用来表示其不能被子类继承或重写。
- 对于类,如果使用了
final
关键字修饰,则该类不能被其他类继承。 - 对于方法,如果使用了
final
关键字修饰,则该方法不能被子类重写。 - 对于属性,如果使用了
final
关键字修饰,则该属性不能在子类中被重新赋值。
使用final
关键字有以下几个好处:
- 可以提高程序的安全性,避免子类对父类的重要方法或属性进行更改。
- 可以提高程序的性能,因为编译器可以对
final
修饰的方法或属性进行优化,减少运行时的开销。 - 可以使程序的设计更加灵活,因为
final
关键字可以限制子类的行为,从而保证代码的正确性和稳定性。
8. 继承和组合
继承和组合是面向对象编程中常用的两种关系。它们的区别如下:
- 继承是一种“is-a”(是一个)的关系,即子类是父类的一种具体化,子类可以继承父类的属性和方法。而组合是一种“has-a”(拥有一个)的关系,即一个类拥有另一个类的对象作为自己的属性或成员。
- 继承是静态的关系,即子类在编译期已经确定了继承关系,而组合是动态的关系,即一个类可以在运行时动态地组合其他类的对象。
- 继承可以方便地实现代码的重用,减少了代码的冗余。但是过多的继承会导致类之间的耦合性增加,影响代码的灵活性。组合能够更灵活地组合各种对象,但是需要更多的代码来处理对象之间的关系。
- 继承可以直接访问父类的属性和方法,但是如果父类的实现发生改变,子类也需要相应地做出调整。组合需要通过调用对象的方法来访问其属性和方法,但是更容易适应变化。
三.多态
1.多态发生的前置条件
Java发生多态的条件包括:
- 继承:多态是通过父类和子类之间的继承关系实现的。
- 重写:子类必须重写父类的方法,才能实现多态。
- 向上转型:使用父类的引用指向子类的对象,从而实现多态。
- 运行时绑定:多态的方法调用在运行时进行绑定,而不是在编译时确定。这意味着程序在运行时才能确定调用的是哪个类的方法。
2.什么是向上转型呢
从上文中我们可以知道发生多态的条件之一就是发生向上转型,那什么是向上转移呢?
向上转型是指将一个子类对象转换为其父类对象的过程,即子类对象赋值给父类类型的变量。这种转型是安全的,因为子类对象具有父类对象所有的属性和方法,因此可以在父类类型的变量中使用。通常向上转型是多态性的基础之一。
举个例子,如果有一个动物类 Animal,和一个子类狗类 Dog,可以这样转型:
Animal animal = new Dog(); // 向上转型,将子类对象赋值给父类对象 //分解写就是 Dog dog = new Dog(); Animal animal = dog;
在这个例子中,Dog 对象 animal 实际上是一个 Animal 类型的变量,但是它仍然可以调用 Dog 类中定义的方法,因为 Dog 类继续了 Animal 类,所以 Dog 类对象拥有 Animal 类的所有属性和方法。
3.什么是重写
重写(override)是指在子类中实现一个与父类中同名、同参数列表的方法,并且这个方法的访问修饰符不能低于父类中的方法,目的是覆盖父类中的方法实现。在运行时,调用该方法时将优先执行子类中的实现。重写方法可以改变父类中的行为,实现多态性和动态绑定。
class Animal { public String name; public int age; public Animal(String name, int age) { this.name = name; this.age = age; } /* 4.private*/ /* 1.final*/ /*2.static*/ public void eat() { System.out.println(this.name+"正在吃...."); } } class Dog extends Animal { public Dog(String name,int age ) { super(name,age); } @Override//重写,建议加上@Override编译器就会检测是否符合重写的语法 public void eat() { System.out.println(this.name+"正在吃狗粮...."); } } class Bird extends Animal { public Bird(String name, int age) { super(name, age); } @Override//重写 public void eat() { System.out.println(this.name + "正在吃鸟粮...."); } } public class text { public static void func(Animal animal){ animal.eat(); } public static void main(String[] args) { func(new Dog("旺财",2)); func(new Bird("布谷",1)); } }
4.多态,继承,封装的实现
// Animal 类定义 public class Animal { private String name; public Animal(String name) { this.name = name; } public void makeSound() { System.out.println("动物发出叫声"); } } // Dog 类继承 Animal 类 public class Dog extends Animal { public Dog(String name) { super(name); } @Override public void makeSound() { System.out.println("汪汪汪"); } } // Cat 类继承 Animal 类 public class Cat extends Animal { public Cat(String name) { super(name); } @Override public void makeSound() { System.out.println("喵喵喵"); } } // 测试类 public class Main { public static void main(String[] args) { Animal dog = new Dog("旺财"); Animal cat = new Cat("咪咪"); dog.makeSound(); // 输出:汪汪汪 cat.makeSound(); // 输出:喵喵喵 } }
5.多态的一些注意事项
1.如果加上了方法上了关键字 final 就不可以发生重写
2.如果是被stastic 修饰的方法也不可以发生重写
3.被private修饰的方法也不可以被重写
4.注意被除private修饰的方法,子类的权限范围大于父类的权限范围
5.不要把构造方法中方法重写
6.重写,建议加上@Override编译器就会检测是否符合重写的语法
七.抽象类和接口
1.抽象类的定义
Java中的抽象类是一种特殊的类,它不能被实例化,只能被继承。抽象类用于定义一些通用的属性和方法,但是这些方法并没有具体的实现,需要子类去实现。抽象类的定义使用关键字abstract来修饰,可以包含抽象方法和非抽象方法。
2.抽象类的语法
public abstract class Animal { //和普通的类一样可以创建成员变量,静态成员变量 public String name; private int age; protected String sex; public static int a; //和普通的类一样可以创建成员方法,静态成员方法 public void func1() { } public static void func2() { } //和普通类不一样的是抽象类还可以创建抽象方法 //抽象方法要在方法的前面加上关键字abstract 并且没有具体的实现 public abstract void func3(); }
- 使用关键字abstract来修饰类,表示这是一个抽象类。
- 抽象类可以包含成员变量、构造方法、抽象方法和非抽象方法。
- 抽象方法的声明以及没有方法体。
- 非抽象方法有具体的实现,可以直接调用。
- 抽象类不能被实例化,只能被继承。
3.抽象类的注意事项
1.抽象类不能被实例化:抽象类不能被直接实例化,因为它包含未实现的抽象方法。只能被用作其他类的父类,子类必须实现抽象方法才能被实例化。
2.子类必须实现抽象方法:如果一个类继承了一个抽象类,它必须实现抽象类中所有的抽象方法,除非子类也声明自己为抽象类。
3.抽象类可以包含非抽象方法:抽象类中可以包含非抽象方法,这些方法有具体的实现。子类可以直接继承这些非抽象方法,也可以选择性地重写它们。
4.抽象类可以包含成员变量和构造方法:与普通类一样,抽象类可以包含成员变量和构造方法。子类可以通过super关键字调用父类的构造方法。
5.抽象类可以被继承:一个抽象类可以被另一个抽象类继承,子类可以继续定义更多的抽象方法,或者实现所有的抽象方法。
4.对抽象类的看法
抽象类是一种不能被实例化的类,它主要用于定义一些共性的属性和方法,以供其子类继承和实现。抽象类本身并不具备完整的实现,而是通过其子类来完善其方法和属性。因此,抽象类可以被看作是一种模板或者规范,用来约束其子类的行为和结构。
抽象类的存在可以帮助程序员更好地进行代码的组织和设计,通过抽象类可以定义出一些通用的行为和属性,减少了代码的重复性,提高了代码的可维护性和扩展性。同时,抽象类也能够在一定程度上约束了子类的行为,使得程序更加健壮和可靠。
总的来说,抽象类是xiaoxie的JAVA系列专栏——CSDN博客●'ᴗ'σσணღ*编程中非常重要的概念,它能够帮助程序员更好地进行代码的组织和设计,提高代码的复用性和可维护性。因此,对于抽象类的使用,程序员需要深入理解其特性和用法,合理地应用到实际的程序设计中。
二.接口
1.接口的定义
接口是指软件系统中不同组件之间互相传递信息的规范和协定。在面向对象编程中,接口用来定义一个类的行为,是类的一种规范化或规范模式。接口中定义了一些方法,但是并不实现,而是由实现该接口的类去实现。
在具体应用中,接口可以描述两个不同的组件之间的交互方式,包括数据格式、协议、参数、返回值等方面的规范。接口可以帮助不同的系统或组件进行互操作,提高软件的可维护性、可扩展性和灵活性。同时,接口的定义还可以帮助开发人员进行模块化的设计和开发,提高代码的复用和可读性。
2.接口的语法
public interface IFly { //接口也可以创建成员变量 //不过成员变量 默认的形式为 public static final //并且需要初始化 因为接口不能实例化对像 String name = " "; //接口可以创建成员方法 //成员方法被 public abstract 修饰 也可以不写,并且没有方法实现 //实现这个接口的类需要重写接口的这个方法 public void work(); //要写具体的方法实现 需要被 public static 所修饰 public static void work1() { } }
其中,InterfaceName
是所定义的接口的名称,// 接口成员
指的是在接口中定义的方法和属性。在接口中定义的方法和属性不包含函数体和实现细节,只是提供了一个对实现类的约束,即定义了实现类必须实现哪些方法和属性。
3.接口的注意事项
1. 确保接口的命名具有描述性,能够清晰地表达其功能和用途。
2. 接口的方法和属性应该按照功能进行分组和命名,以便于理解和使用。
3. 接口的设计应该尽量简洁和易于理解,避免过度复杂或冗余的设计。
4. 在设计接口时,需要考虑到未来可能的扩展和变化,以便接口能够灵活地适应需求的变化。
5. 接口的文档应该清晰地描述每个方法和属性的作用和用法,以便其他开发人员能够正确地使用接口。
6. 在实现接口时,需要确保按照接口定义的要求进行实现,以确保接口的一致性和可靠性。
7. 接口的版本管理也是一个重要的考虑因素,需要确保接口的变化不会对已有的实现造成影响。
8. 在使用接口时,需要遵循接口的规范和约定,以确保接口的正确使用和调用。
4.父类和接口的区别
1.在Java中子类只能继承一个父类,子类却可以实现多个接口
2.抽象类的成员属性和方法和普通类一样 可以创建成员变量和成员方法,而接口的成员属性是被 public stasic final 和 public abstract 所修饰的
5.对接口的看法
接口是一种非常重要的编程概念,它可以帮助开发人员实现代码的模块化和复用,提高代码的可维护性和可扩展性。
接口提供了一种规范化的方式来定义类之间的交互和通信方式,使得不同的类可以通过实现同一个接口来实现相同的功能。这种方式可以大大减少代码的重复和冗余,同时也可以提高代码的可读性和可理解性。
另外,接口还可以帮助开发人员实现代码的解耦和模块化,使得不同的模块之间可以独立开发和测试,从而提高代码的质量和可靠性。同时,接口的使用也可以促进团队合作和代码复用,使得开发效率得到提高。
总之,作为一种重要的编程概念,接口在软件开发中具有非常重要的作用,它可以帮助开发人员实现代码的复用和模块化,提高代码的可维护性和可扩展性,促进团队合作和开发效率的提高。
三.接口和抽象类的结合运用
接口和抽象类都是面向对象编程中的重要概念,它们可以用于实现多态和封装。在某些情况下,将接口和抽象类结合起来使用可以达到更好的效果。
接口和抽象类的区别在于,接口只能定义方法和常量,而抽象类可以定义具体方法和成员变量。因此,可以使用抽象类来实现接口中的某些方法,然后在子类中重写剩余方法。
例如,假设我们有一个图形接口 Shape,其中定义了一个计算面积的方法 getArea()。我们可以将该接口改为抽象类,并提供一个具体方法 getPerimeter() 来计算周长。这样,子类就可以继承抽象类并只需要实现计算面积的方法。
示例代码如下:
public abstract class Shape { public double getPerimeter() { return 0; } public abstract double getArea(); } public class Circle extends Shape { private double radius; public Circle(double radius) { this.radius = radius; } @Override public double getArea() { return Math.PI * radius * radius; } @Override public double getPerimeter() { return 2 * Math.PI * radius; } } public class Rectangle extends Shape { private double length; private double width; public Rectangle(double length, double width) { this.length = length; this.width = width; } @Override public double getArea() { return length * width; } @Override public double getPerimeter() { return 2 * (length + width); } }
在上面的示例中,我们将 Shape 接口改为抽象类,并添加了一个具体方法 getPerimeter()。子类 Circle 和 Rectangle 继承自 Shape,并实现了 getArea() 方法和重写了 getPerimeter() 方法。
通过这种方式,我们可以在抽象类中实现一些通用的方法,同时还能保留接口的灵活性。这种结合运用可以使代码更加简洁和易于扩展。
八.String类
String类是Java中非常重要的一个类,它代表字符串。String类是Java中唯一不用new关键字就可以创建对象的类。在Java中,字符串是使用Unicode字符编码表示的。String类有许多方法可以用来操作字符串,例如连接字符串、截取字符串、查找字符串等等。在Java中,字符串是不可变的,这意味着一旦创建了一个字符串,它就不能被修改。如果需要修改字符串,需要创建一个新的字符串对象。字符串具有很高的使用频率,也是Java中非常重要的数据类型之一。
1.说明
字符串类的相关知识很重要,在面试题或者是笔试题里出现的频率很高,所以需要我们熟练的掌握它。
2.String的构造方法
String s = "hello"; String s1 = new String("hello"); char[] arr = {'h','e','l','l','o'}; String s2 = new String(arr);
3.Sting类的常用方法
方法 | 功能 |
char charAt(int index) |
返回 index 位置上字符,如果 index 为负数或者越界,抛出 IndexOutOfBoundsException 异常 |
int indexOf(int ch) |
返回 ch 第一次出现的位置,没有返回 -1 |
int lastIndexOf(int ch) |
从后往前找,返回 ch 第一次出现的位置,没有返回 -1 |
String replaceAll(String regex, String replacement) |
替换所有的指定内容 |
String replaceFirst(String regex, String replacement) |
替换指定内容 |
String[] split(String regex, int limit) |
将字符串以指定的格式,拆分为 limit 组 |
String[] split(String regex) |
将字符串全部拆分 |
String substring(int beginIndex) |
从指定索引截取到结尾 |
String substring(int beginIndex, int endIndex) |
截取部分内容 |
String trim() |
去掉字符串中的左右空格 , 保留中间空格 |
String toUpperCase() |
字符串转大写 |
String toLowerCase() |
字符串转小写 |
显示详细信息
以上就是字符串常用的库函数了,但需要注意的是String是一种不可变对象. 字符串中的内容是不可改变。字符串不可被修改。
九.异常
ava异常是指在程序运行过程中出现的错误或异常情况,如空指针异常、数组越界异常等。Java异常处理机制可以使程序在出现异常时不会立即崩溃,而是能够通过异常处理机制来捕获异常并进行处理,从而提高程序的健壮性和可靠性。
Java异常处理机制主要包括以下几个方面:
- 异常类的继承关系:Java中所有异常类都继承自Throwable类,其中又分为Error和Exception两个子类,其中Error表示程序无法处理的错误,Exception表示程序可以处理的异常。
- 异常处理语句:Java中提供了try-catch-finally语句来处理异常,其中try块中放置可能出现异常的代码,catch块中捕获异常并进行处理,finally块中放置无论是否出现异常都需要执行的代码。
- 抛出异常:当程序出现异常时,可以通过throw语句手动抛出异常,并在catch块中进行处理。
- 自定义异常:Java中允许自定义异常类,可以根据业务需求来定义自己的异常类,并在程序中使用。
- 异常链:Java中的异常可以形成异常链,即一个异常引发另一个异常,可以通过getCause()方法获取异常链中的前一个异常。
总之,Java异常处理机制是保证程序健壮性和可靠性的重要机制之一,掌握好异常处理机制可以帮助程序员更好地处理异常情况,提高程序的稳定性和可维护性
十.关于JavaSE阶段的一些需要注意的点
1.【面试题】JDK、JRE、JVM之间的关系?
Java Development Kit (JDK): JDK 是 Java 开发工具包,是整个 Java 平台的核心组成部分。它包含了用于开发 Java 应用程序所需的软件开发工具,包括:
- Java Runtime Environment (JRE): JRE 是 Java 运行环境,它是运行 Java 应用程序所必需的组件。它包含了:
- Java Virtual Machine (JVM): JVM 是 Java 虚拟机,它是实现 Java 语言跨平台特性的关键部分。JVM 负责解释和执行字节码(.class 文件),并为 Java 程序提供了一个独立于具体操作系统和硬件平台的运行环境。
总的来说即:JDK包含JRE,而JRE又包含JVM如果你需要编写和编译 Java 代码,你需要安装 JDK;如果你只需要运行 Java 程序,则只需要安装 JRE 即可。而所有的 Java 程序都需要在 JVM 上运行,这就是所谓的“一次编写,到处运行”(Write Once, Run Anywhere, WORA)的特性。
2.浅拷贝和深拷贝的区别
浅拷贝和深拷贝是两种不同的复制对象的方法,它们的主要区别在于是否创建了原始对象中所引用的对象的新副本。以下是它们之间的主要差异:
浅拷贝
- 定义:浅拷贝是指重新分配一块内存,创建一个新的对象,但这个新对象中的元素是原对象中各个子对象的引用。
- 行为:当对可变类型的子对象进行操作时,修改会影响到原对象,因为它们共享同一份数据。
- 示例:
- 对于列表(list)来说,浅拷贝会创建一个新列表,但是其中的元素仍然是原来列表中元素的引用。
- 对于字典(dict)来说,浅拷贝会创建一个新字典,但是其中的键值对仍然是原来字典中键值对的引用。
深拷贝
- 定义:深拷贝是指重新分配一块内存,创建一个新的对象,并且将原对象中的元素,以递归的方式,通过创建新的子对象拷贝到新对象中。因此,新对象和原对象没有任何关联。
- 行为:即使对可变类型的子对象进行操作,也不会影响到原对象,因为它们各自拥有独立的数据副本。
- 示例:
- 对于列表(list)来说,深拷贝会创建一个新列表,并且其中的元素也都是原始元素的完整副本。
- 对于字典(dict)来说,深拷贝会创建一个新字典,并且其中的键值对也是原始键值对的完整副本。
3.重载和重写的区别
重载(Overloading)和重写(Overriding)是面向对象编程中的两个重要概念,它们都与方法的定义和使用有关。下面是两者的区别:
1. 定义不同
- 重载:在同一类中,允许存在多个同名的方法,但这些方法的参数列表必须不同(即参数的数量、类型或顺序至少有一个不相同)。这样,编译器可以根据调用时提供的参数类型和数量来决定具体执行哪个方法。
- 重写:在子类中重新实现父类的方法,且方法名称、返回类型和参数列表必须与被覆盖的方法完全一致。这意味着当子类对象调用该方法时,会执行子类中定义的代码而不是父类中的代码。
2. 范围不同
- 重载:仅在一个类内部发生。
- 重写:发生在继承关系中,涉及父类和子类之间的关系。
3. 多态性不同
- 重载:属于静态多态,也称为编译时多态。在编译阶段就已经确定了要调用哪个方法。
- 重写:属于动态多态,也称为运行时多态。只有在程序运行时才会根据实际的对象类型确定调用哪个方法。
4. 参数不同
- 重载:要求参数列表不同,可以有不同的参数个数、类型或者顺序。
- 重写:不能改变参数列表,必须保持与父类中被覆盖方法的参数列表完全一致。
5. 返回值类型
- 重载:返回值类型可以不同,也可以相同。
- 重写:返回值类型必须与被覆盖的方法一致,或者为其子类型。
6. 修饰符
- 重载:对方法的访问修饰符没有特定的要求。
- 重写:要求重写方法的访问修饰符大于等于被重写的父类方法。
7. 目的不同
- 重载:为了解决同一功能的不同实现方式,通过不同的参数列表来区分。
- 重写:为了在子类中提供一种不同于父类的行为,通常是为了扩展或修改父类的功能。
总结起来,重载是在同一个类内提供多种实现方式以适应不同的参数类型,而重写则是在继承体系中使得子类能够替换父类的某些行为,从而实现多态性。
4.this 和 super 的区别
this 关键字
- 作用:
this
关键字用于引用当前类的对象实例。它可以用来调用当前对象的方法或访问当前对象的成员变量。 - 使用场合:
- 在非静态方法中(包括构造函数),可以使用
this
来区分局部变量与成员变量。 - 在构造器中,可以用
this
调用另一个重载的构造器。
- 限制:不能在类的静态方法、静态代码块或声明为静态的变量中使用
this
关键字。
super 关键字
- 作用:
super
关键字用于引用父类对象实例。它可以用来调用父类的方法或者访问父类的成员变量。 - 使用场合:
- 在子类中覆盖了父类的方法时,可以通过
super
关键字调用父类的方法实现。 - 在子类的构造器中,通过
super
调用父类的构造器初始化父类的成员变量。
- 限制:同
this
一样,不能在类的静态方法、静态代码块或声明为静态的变量中使用super
关键字。
总结起来,this
关键字是用来引用当前类的对象实例,而super
关键字则是用来引用父类的对象实例。两者都可以用于访问和操作对象的属性和方法,但是分别对应的是当前类和父类。
5.继承和接口的区别
继承
- 定义:继承是指一个类(子类)从另一个类(父类)中继承属性和方法的过程。
- 语法:在Java中使用
extends
关键字来表示继承关系。 - 特点:
- 单继承:一个类只能直接继承一个父类(不考虑多层继承时的间接父类)。
- 多级继承:一个类可以间接地继承多个类。
- 父类的私有成员变量和方法不能被子类访问或覆盖。
- 作用:通过继承,子类可以直接获得父类的所有非私有的属性和方法,无需重新编写相同的代码。
接口
- 定义:接口是一种契约,它定义了一组行为规范。实现接口的类必须提供接口所要求的功能。
- 语法:在Java中使用
interface
关键字来声明接口。 - 特点:
- 接口没有构造器,不能实例化。
- 接口中所有方法默认为抽象的,并且不允许包含任何实现。
- 一个类可以实现多个接口。
- 作用:接口提供了统一的行为标准,使得不同类型的对象能够共享相同的行为方式。
区别总结
- 继承关注的是“是什么”的关系,即子类是一个特殊的父类;而接口关注的是“能做什么”的能力,即实现了接口的类具有某种功能。
- 子类继承自父类后,自动拥有父类所有的非私有属性和方法;实现接口的类则需要手动提供接口中所定义的方法的实现。
- 类与类之间的继承关系是单向的,而类与接口的关系则是多对一或多对多的。
- 类只能单一继承,但可以实现多个接口。
- 在设计上,通常推荐优先使用组合、委托和接口而不是继承,因为继承容易导致耦合度过高,不利于系统的维护和扩展。
6.String、StringBuffer、StringBuilder的区别
- 不可变性:
String
:是不可变的。一旦创建了一个String对象,就不能更改其内容。每次对String进行修改都会创建一个新的String对象。StringBuffer
和StringBuilder
:这两个类的对象可以被多次修改。
- 线程安全性:
String
:由于它的不可变性,因此它是线程安全的。StringBuffer
:是线程安全的,在多线程环境下使用时不需要额外同步。StringBuilder
:是非线程安全的,它在单线程环境下比StringBuffer更快,因为它不需要执行同步操作。
- 性能:
String
:由于每次修改都需要创建新的对象,所以频繁修改字符串时可能会导致大量内存分配和垃圾回收,影响性能。StringBuffer
和StringBuilder
:它们内部维护一个字符数组,可以通过动态扩展来适应字符串的变化,所以在频繁修改字符串时效率更高。
- 应用场景:
String
:适合于那些不会改变的字符串常量,或者字符串操作不频繁的情况。StringBuffer
:适用于多线程环境下的字符串操作,比如在一个服务器应用程序中处理用户请求。StringBuilder
:适用于单线程环境下的字符串操作,特别是当需要频繁修改字符串且不需要考虑线程安全的时候。
总结起来,当你需要处理不变的字符串或只读字符串时,应使用String;如果你需要频繁地修改字符串,并且是在多线程环境中,应使用StringBuffer;如果你在单线程环境中并且希望提高字符串操作的速度,则应使用StringBuilder。
十一.结语
以上就是博主这一个多月学习JAVASE的所有的内容了,希望你能够对你有所帮助,感谢阅读,祝你一天愉快