在Java中,包(Package)
是用于组织和管理类以及其他Java
程序元素的一种机制。它是一种命名空间,可以将相关的类和接口组织在一起。Java包通常对应着目录结构
。例如,com.example.myapp
包可能对应着文件系统中的 com/example/myapp
文件夹,类文件会按照包名的层次结构存储在相应的文件夹中。
区分相同名字的类
当类很多时,可以很好的管理类(比如Java
的API
官方文档)
控制访问的范围。
Java中的访问修饰符(如 public
、protected
、private
、默认访问控制符等)可用于限制类和接口在包内的可见性。类和接口可以在同一包中直接访问彼此,但在其他包中,要想访问就需要使用合适的访问修饰符。
package com.example.myapp;
说明:
1、packege 关键字,表示打包
2、com.myapp 表示包的名字
包的本质就是创建不同的文件夹/目录,来保存类文件
只能包含数字、字母、下划线、小圆点,不能是数字开头,不能是关键字或者保留字
一般是小写字母加上小圆点
比如:com.sina.crm.user
java.lang.*
是java
的基本包,默认引用,不需要再引入java.util.*
系统提供的工具包,工具类,比如 Scanner
java.net.*
网络包,用于网络的开发java.awt.*
java的界面开发,GUI//引用包的语法:import+包的名字
import java.util.Scanner; //只是引用一个类Scanner
import java.util.*; //引用java.util的所有包(不建议)
Java 中有四种访问修饰符:
public
(公共):
private
(私有):
protected
(受保护):
public
、private
或 protected
),则该成员将具有默认访问权限。访问级别 | 访问控制修饰符 | 同类 | 同包 | 子类 | 不同包 |
---|---|---|---|---|---|
公开 | public |
√ | √ | √ | √ |
受保护 | protected |
√ | √ | √ | × |
默认 | 没有修饰符 | √ | √ | × | × |
私有 | private |
√ | × | × | × |
public
才能修饰类面向对象的三大特征:封装、继承、多态
封装是指将数据和操作数据的方法(即行为)捆绑在一起,并限制对外部的访问。
封装的步骤通常包括:
public class Person {
private String name; // 将数据声明为私有
// 提供公共方法来访问和修改私有数据
public String getName() {
return name; // getter 方法用于获取数据
}
public void setName(String newName) {
this.name = newName; // setter 方法用于设置数据
}
}
继承是指一个类(子类)可以通过继承另一个类(父类)的特性和行为。继承支持代码重用和层次化,使得代码更具扩展性和灵活性。
extends
继承父类的成员变量和方法// 父类(基类、超类)
class Parent {
// 父类的成员变量和方法
}
// 子类(派生类)继承父类(基类)
class Child extends Parent {
// 子类新增的成员变量和方法
}
子类继承了父类所有的属性和方法,非私有的属性和方法可以直接访问,但是父类私有的方法和属性不能直接访问,需要父类提供公共的方法去访问
子类必须调用父类的构造器, 完成父类的初始化
当创建子类对象时,不管使用子类的哪个构造器,默认情况下总会去调用父类的无参构造器,如果父类没有提供无参构造器,则必须在子类的构造器中用super
去指定使用父类的哪个构造器完成对父类的初始化工作,否则编译不通过。
如果希望指定去调用父类的某个构造器,则显式的调用一下: super
(参数列表)
super
在使用时,必须放在构造器第一行(super
只能在构造器中使用)
super()
和this()
都只能放在构造器第一行,因此这两个方法不能共存在一个构造器
java
所有类都是Object
类的子类, Object
是所有类的基类.
父类构造器的调用不限于直接父类!将一直往上追溯直到Object 类(顶级父类)
子类最多只能继承一个父类(指直接继承),即java
中是单继承机制。
思考:如何让A 类继承B 类和C 类? 【A 继承B, B 继承C】
不能滥用继承,子类和父类之间必须满足is-a 的逻辑关系
Person is a Music //不合理
Father is a Person //合理
Object
的构造器,然后是GrandPa
的构造器,然后是Father
的构造器,最后才是Son
的构造器代码如下:
/**
* 讲解继承的本质
*/
public class ExtendsTheory {
public static void main(String[] args) {
Son son = new Son();
//按照查找关系来返回信息
//(1)首先看子类是否有该属性,如果子类有这个属性,并且可以访问,则返回信息
//(2)如果子类没有这个属性,就看父类有咩有属性(如果有并且可以访问,则返回信息)
//(3)如果父类没有,就按照(2)的规则,继续往上找上级的父类,直到object类
System.out.println(son.name); //返回是大头儿子
System.out.println(son.age); //返回是39
System.out.println(son.hobby); //返回的是旅游
}
}
class GrandPa{
String name = "大头爷爷";
String hobby = "旅游";
}
class Father extends GrandPa{
String name = "大头爸爸";
int age = 39;
}
class Son extends Father{
String name = "大头儿子";
}
它允许不同类的对象对同一消息作出不同的响应。多态性是通过“一个接口,多种实现”来实现的。多态可以表现为方法的多态和对象的多态。
=
的左边,运行类型看 =
的右边Animal animal = new Dog() 解释:animal编译类型是Animal,运行类型是Dog
animal = new Cat(); 解释:Animal的运行类型变成了Cat,但是编译类型仍然是Animal
多态的前提是:两个对象存在继承关系
父类类型 引用名 = new 子类类型();
举例:
//父类
public class Animal {
String name;
public void eat(){
System.out.println("Animal 吃");
}
public void run(){
System.out.println("Animal 跑");
}
public void show(){
System.out.println("Animal Show");
}
}
//子类
public class Cat extends Animal{
int age;
public void eat(){
System.out.println("Cat 吃");
}
public void special(){
System.out.println("Cat special");
}
}
//实现
public class Test {
public static void main(String[] args) {
Animal animal = new Cat();
//无法解析Car中独有的方法和属性
// animal.special(); 报错
// animal.age; 报错
//重写,首先是先找car里面有的方法,运行的时候看子类
animal.eat(); //首先父类有这个方法,然后子类重写了,最终运行的时候还是看子类的运行结果
}
}
向下转型是针对于向上转型之后的,重新转回本来运行类型的对象。
子类类型 引用名 = (子类类型) 父类引用;
//实现
public class Test {
public static void main(String[] args) {
Animal animal = new Cat();
//再继续向下转型,引用必须是当前目标类型的对象
Cat cat = (Cat) animal
//可以调用子类类型中所有的成员
animal.special();
animal.age;
animal.eat();
}
}
属性的值没有重写,属性值直接看编译类型
//假设Cat为Animal的子类
Cat子类 age = 10;
Animal 父类 age = 20;
//向上转型
Animal animal = new Cat();
//向下转型
Cat cat = (Cat)animal;
System.out.println(animal.age); //因为编译类型为animal,所以输出为animal的age=20
System.out.println(cat.age); //重新修改编译类型,现在的编译类型为cat,所以age=10
举例:
public class DynamicalBand {
public static void main(String[] args) {
A a = new B();
//实现逻辑:a.sum()的运行对象是b,但是b中没有sum方法,所以从父类找,父类的sum方法里面,有个getI方法,这个方法首先看运行对象里面是否有,这里有的话,get的运行对象的i,所以最后的结果是30
System.out.println(a.sum());
//实现逻辑:a.sum1()的运行对象是b,但是b中没有sum1方法,所以从父类找,父类的sum1里面有个i,但是属性并没有动态绑定机制,所以直接是采用A父类的i,所以结果是20
System.out.println(a.sum1());
}
}
class A{//父类
public int i = 10;
public int sum(){
return getI() + 10;
}
public int sum1(){
return i + 10;
}
public int getI(){
return i;
}
}
class B extends A{//父类
public int i = 20;
// public int sum(){
// return i + 20;
// }
// public int sum1(){
// return i + 10;
// }
public int getI(){
return i;
}
}
super
是 Java
中的关键字,用于引用父类的成员(方法、变量)或调用父类的构造方法。
1、访问父类的属性,但不能访问父类的
private
属性 super.属性名;
2、调用父类的方法,不能访问父类的
private
方法 super.方法名(参数列表);
3、访问父类的构造器
super(参数列表);只能放在构造器的第一句,而且只能出现一句。
示例:
public class Parent {
int value = 10;
Parent() {
System.out.println("Parent constructor");
}
void display() {
System.out.println("Value in parent: " + value);
}
}
public class Child extends Parent {
int value = 20;
Child() {
super(); // 调用父类的构造方法
System.out.println("Child constructor");
}
void display() {
super.display(); // 调用父类的 display 方法
System.out.println("Value in child: " + value);
System.out.println("Value in parent using super: " + super.value); // 访问父类的 value
}
}
super
,如果没有重名,使用super
、this
、直接访问都是一样的效果。super
访问**不限于直接父类,如果爷爷类与本类有同名的成员,也可以使用super
去访问爷爷类的成员。**如果多个基类都有同名的成员,使用super
遵循就近原则 A->B->C
,同时也需要遵循访问权限的相关规则。不同点 | this | super |
---|---|---|
访问属性 | 访问本类中的属性,如果本类没有此属性则从父类继续查找 | 从父类开始查找属性 |
调用方法 | 访问本类中的方法,如果本类没有此方法则从父类继续查找 | 从父类开始查找方法 |
调用构造器 | 调用本类构造器,必须放在构造器的首行 | 调用父类的构造器,必须放在子类构造器的首行 |
特殊 | 表示当前对象 | 子类中访问父类对象 |
方法重写(Method Overriding)指的是子类可以重新定义(覆盖)从其父类继承而来的方法。当子类声明了一个与父类中某个方法签名完全相同的方法时,就发生了方法重写。
举例:
class Animal {
void makeSound() {
System.out.println("Some sound");
}
}
class Dog extends Animal {
// 方法重写
@Override
void makeSound() {
System.out.println("Bark");
}
}
子类的方法的形参列表、方法名称要和父类方法的形参列表,方法名称完全一样
子类方法的返回类型和父类方法的返回类型一样,或者是父类返回类型的子类
比如:父类的返回类型是
Object
,子类的返回类型是String
public Object getInfo(){} public String getInfo(){}
子类方法不能缩小父类的方法的权限,但是可以扩大
class Animal {
protected void makeSound() {
System.out.println("Some sound");
}
}
class Dog extends Animal {
// 这是合法的重写,子类可以扩大父类方法的访问权限
public void makeSound() {
System.out.println("Bark");
}
}
名称 | 发生范围 | 方法名 | 形参列表 | 返回类型 | 修饰符 |
---|---|---|---|---|---|
重载(Overload) | 本类 | 必须一样 | 类型、个数或者顺序至少有一个不同 | 无要求 | 无要求 |
重写(override) | 父子类 | 必须一样 | 相同 | 相同或者子类的返回类型是父类返回类型的子类 | 子类方法不能缩小父类方法的访问类型 |
equals()
方法是用于比较 两个对象是否在逻辑上相等的方法。该方法定义在 Object
类中,因此所有 Java
类都继承了这个方法。然而,它通常需要在类中进行重写,以便根据对象的实际内容(而不是引用地址)来判断相等性。
equals
与==
的比较
==
既可以判断基本类型,又可以判断引用类型==
如果判断基本类型,判断的是值是否相等==
如果是判断引用类型,判断的是地址是否相等,即判定是否为同一个对象equals
是Object
类中的方法,只能判断引用类型。默认判断的是地址是否相等,子类会进行重写,判断两者内容是否相同。hashCode
主要用来提高具有哈希结构的容器的效率**Object
源码:**默认返回:全类名+@+哈希值的十六进制
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
子类往往会重写toString
方法,打印对象或者拼接对象时,都会自动调用该对象的toString
方法
System.out.println(monster); //默认调用monster.toString()
重写示例:
//快捷键 Alt+Insert
public String toString() { //重写toString,一般默认是class类名以及属性输出
return "Employee{" +
"name='" + name + '\'' +
", salary=" + salary +
'}';
}
finalize
被设计用来在对象被垃圾回收之前进行资源释放或清理操作。程序员可以在finalize
方法里面写自己的一些业务逻辑(如:释放资源,数据库连接,或者打开的文件等)
我们在实际开发中,几乎不会运用 finalize , 所以更多就是为了应付面试.