这里写目录标题
- 1.包
- 1.1包的命名
- 1.2Java中常用包
- 1.3细节
- 2.访问修饰符
- 3.封装
- 3.1构造器与setXxx结合
- 4.继承
- 4.1细节
- 4.2练习
- 5.super关键字
- 5.1细节
- 5.2super和this的比较
- 6.方法重写/覆盖
- 6.1重载和重写的区别
- 7.多态
- 7.1向上转型
- 7.2向下转型
- 7.3instanceOf比较操作符
- 7.4Java动态绑定机制
- 7.5多态数组
- 7.6多态参数
- 8.Object类
- 8.1equals方法
- 8.2自己重写equals方法
- 8.3hashCode方法
- 8.4toString方法
- 8.5finalize方法
- 9.断点调试(debug)
1.包
1.包的作用:
①区分相同名字的类
②当类很多时,可以更好的管理类
③控制访问范围
package 包名
包的本质创建不同的文件夹来保存类文件
1.1包的命名
规则:包含数字,字母,下划线,小圆点,不
能以数字开头,不能是关键字或保留字
规范:小写字母➕小圆点
com.公司名.项目名.业务模块名
1.2Java中常用包
java.lang*:基本包,默认引入
java.util.*:工具包,工具类(Scanner)
java.net*:网络包,网络开发
java.awt*:Java的页面开发,GUI
import java.util.Scanner;
//只会引入java.util包下的Scanner(推荐)
import java.util.*;
//把java.util包下的所有类都引入
import java.util.Arrays;
int[] arr = {9,68,8,102,46};
Arrays.sort(arr);//自动排序
for(int i;i < arr.length;i++){
System.out.print(arr[i] + " ");
//输出8 9 46 68 102
}
1.3细节
1.package语句放在最上面,一个类中最多只有一句package
2.import放在package下面,在类定义前,可以有多句,没有顺序要求
2.访问修饰符
用于控制方法和属性的使用权限
1.public:公共级别,对外公开
2.protected:受保护级别,对子类和同一个包中的类公开
3.默认:向同一个包中的类公开
4.private:只有类本身可以访问,不对外公开
可以修饰属性和方法,只有public和默认可以修饰类
面向对象的三大特征:封装,继承,多态
3.封装
把属性和方法封装在一起,通过授权方法来操作
好处:①隐藏实现细节②可以对数据进行验证,保证安全合理
步骤:
①将属性进行私有化private
②提供一个公共的set方法,用于对属性判断并赋值
public void setXxx(类型 参数名){
//Xxx表示某个属性
//加入数据验证的业务逻辑
属性 = 参数名;
}
③提供一个公共的get方法,用于获取属性的值
public 数据类型 getXxx(){//权限判断
return xx;
}
3.1构造器与setXxx结合
import java.util.*;
/*
不能随便查看人的年龄,工资
年龄在1-120岁之间,否则给999
工资不能直接查看
name的长度在2-6个字符之间
*/
public class t1封装信息 {
public static void main(String[] args) {
Person p = new Person();
p.setName("Jack");
p.setAge(45);
p.setSal(5000);
System.out.println(p.info());
System.out.println(p.getSal());
Person p1= new Person("张三",580,6000);
System.out.println(p1.info());
}
}
class Person{
public String name;
private int age;
private double sal;
public Person(){
}
//构造器与setXxx结合
public Person(String name,int age,double sal){
setName(name);
setAge(age);
setSal(sal);
}
//姓名
public String getName(){
return name;
}
public void setName(String name){
if(name.length() >= 2 && name.length() <= 6){
this.name = name;
}else{
System.out.println("名字长度在2-6个字符之间");
this.name = "无";
}
}
//年龄
public int getAge(){
return age;
}
public void setAge(int age){
if(age >= 1 && age <= 120){
this.age = age;
}else{
System.out.println("年龄在1-120岁之间");
this.age = 999;
}
}
//工资
public double getSal(){
//判断信息是否正确
return sal;
}
public void setSal(double sal){
this.sal = sal;
}
//输出
public String info(){
return "姓名:" + name + "年龄:" + age + "工资:" + sal;
}
}
4.继承
class 子类 extends 父类{
}
便利:①代码复用性,扩展性,维护性提高
4.1细节
1.子类继承了父类所有的属性和方法,私有属性和方法不能在子类直接访问,要通过父类提供的公共方法去访问
2.子类必须调用父类的构造器,完成对父类的初始化
public class Test{
public static void main(String[] args) {
C c = new C();
c.say();
}
}
public class C extends F{
C(){
System.out.println("子类构造器被调用");
}
public void say(){
System.out.println(n1 + " " + n2 + " " + n3);
System.out.println(getN4());
test100();
test200();
test300();
sayOk();
}
}
public class F{
public int n1 = 100;
protected int n2 = 200;
int n3 = 300;
private int n4 = 400;
F(){
System.out.println("父类构造器被调用");
}
public int getN4(){
//通过父类提供的公共方法去访问
return n4;
}
public void test100(){
System.out.println("test100");
}
protected void test200(){
System.out.println("test200");
}
void test300(){
System.out.println("test300");
}
private void test400(){
System.out.println("test400");
}
public void sayOk(){
//通过父类提供的公共方法去访问
test400();
}
}
3.当创建子类对象时,不管使用子类的哪个对象,都会调用父类的无参构造器;如果父类没有无参构造器,则必须在子类的构造器中用super()去指定使用父类的哪个构造器,否则,编译不通过
4.要指定调用父类的某个构造器,super(实参)
5.super()和this()放在构造器第一行,且两个方法不能在同一个构造器
6.super只能在构造器中使用
7.Object是所有类的父类
8.子类只能直接继承一个父类,Java是单继承
public class C{
C(){
super(60);
}
}
public class F{
F(int age){
}
}
先加载父类
4.2练习
class A{
A(){
System.out.println("a");
}
A(String name){
System.out.println("a name");
}
}
class B extends A{
B(){
this("abc");//调用B的有参构造器
System.out.println("b");
}
B(String name){
//有隐藏的super();调用父类无参构造器
System.out.println("b name");
}
}
B b = new B();//调用无参构造器
//结果:a,b name,b
5.super关键字
代表父类的引用,用于访问父类的属性,方法,构造器,但不能访问父类的private
访问属性:super.属性名;
访问方法:super.方法名(参数列表);
访问构造器:super(参数列表;)
5.1细节
1.好处:分工明确,父类属性由父类初始化,子类属性由子类初始化
2.当子类和父类成员重名时,访问父类成员,必须用super,没有重名,则super,this,直接访问都一样
5.2super和this的比较
6.方法重写/覆盖
1.子类方法的参数列表和名称和父类完全一样
2.子类方法的返回类型和父类方法的返回类型一致,或是父类返回类型的子类
3.子类方法不能缩小父类方法的访问权限
public class C extends F{
public void cry(){
//方法重写
//父类是public,子类就不能是protected,默认,private
System.out.println("喵喵叫...");
}
public String m1(){
//String是Object的子类
return null;
}
public A m2(){
//返回类型和父类完全一致
return null;
}
public B m2(){
//B是父类返回类型的子类
return null;
}
}
public class F{
public void cry(){
System.out.println("旺旺叫...");
}
public Object m1(){
return null;
}
public A m2(){
return null;
}
}
class A{
}
class B extends A{
}
6.1重载和重写的区别
7.多态
方法或对象具有多种形态,前提是双方存在继承关系,建立在封装和继承基础之上
方法的多态:重载和重写
对象的多态:
1.编译类型 = 运行类型
2.一个对象的编译类型和运行类型可以不一致
3.编译类型在定义对象时就确定了
4.运行类型是可以变化的
//Dog和Cat继承了Animal类
Animal animal = new Dog();
/*
Animal是Dog的父类
父类的引用指向子类的对象,子类的对象可以赋给父类的引用
编译类型是Animal,运行类型是Dog
*/
animal = new Cat();
//编译类型仍然是Animal,运行类型变成了Cat
7.1向上转型
父类的引用指向子类的对象
父类类型 引用名 = new 子类类型();
可以调用父类的所有成员,不可以调用子类的特有成员
7.2向下转型
子类类型 引用名 = (子类类型) 父类引用;
1.只能强转父类的引用,不能强转父类的对象
2.父类的引用必须指向当前目标类型的对象
3.可以调用子类类型所有成员
public class T{
Cat cat = new Cat ();
Animal a = cat;
//向上转型,把子类的引用赋给父类的引用
Animal animal = new Cat();
Object obj = new Cat();//Object是超类
//向上转型
animal.sleep();//睡
animal.eat();//吃鱼
//animal.show();不可以,show是子类的特有方法
}
Cat cat = (Cat) animal;
//编译类型是Cat,运行类型是Cat
//只能强转父类的引用
//animal指向了Cat的对象
cat.show();
class Cat extends Animal{
public void eat(){
System.out.println("吃鱼");
}
public void show(){
System.out.println("展示");
}
}
public class Animal{
public void sleep(){
System.out.println("睡");
}
class void eat(){
System.out.println("吃");
}
}
属性没有重写,看编译类型
F f = new C();
System.out.println(c.count);//10
//编译类型是F
public class F{
int count = 10;
}
class C extends F{
int count = 20;
}
7.3instanceOf比较操作符
判断对象的运行类型是否为XX类型或XX类型的子类
C c = new C();
System.out.println(c instanceof F);//true
F f = new C();
System.out.println(f instanceof F);//true
String str = "hello"
System.out.println(str instanceof Object);//true 运行类型是String
class C extends F{
}
public class F{
}
Object obj = "hello";
//向上转型 Object obj = new String("hello");
Object object = new Integer(5);//向上转型
//父类引用指向Integer
String str = (String) object;//不可以
//指向Integer的父类引用转成String
//父类引用必须指向当前目标类型的对象
Integer str1 = (Integer) object;
属性看编译类型,方法看运行类型
Sub s = new Sub();
Base b =s;
//向上转型,把子类的引用赋给父类的引用
System.out.println(b == s);//true
System.out.println(b.count);//10
//属性看编译类型,编译类型是Base
b.display();//20
//方法看运行类型,运行类型是Sub
class Sub extends Base{
int count = 20
public void display(){
System.out.println(this.count);
}
}
public class Base{
int count = 10;
public void display(){
System.out.println(this.count);
}
}
7.4Java动态绑定机制
1.调用对象方法时,会和该对象的内存地址(运行类型)绑定
2.调用对象属性时,没有动态绑定机制,哪里声明哪里调用
A a = new B();
System.out.println(a.sum());//30
/*
1.在B类里找sum()方法,没找到
2.在A类里找sum()方法,找到了
3.返回getI() + 10;
4.调用了getI()方法,和运行类型绑定
5.在B类里找getI()方法
6.返回i,i = 20
7.所以20 + 10 = 30
*/
System.out.println(a.sum1());//20
/*
1.在B类里找sum1()方法,没找到
2.在A类里找sum1()方法,找到了
3.返回i + 10;
4.属性i没有动态绑定机制,所以i是A类里的
5.i = 10,返回10 + 10 = 20
*/
class B extends A{
public int i = 20;
public int getI(){
return i;
}
}
public class A{
public int i = 10;
public int sum(){
return getI() + 10;
}
public int sum1(){
return i + 10;
}
public int getI(){
return i;
}
}
7.5多态数组
数组的定义类型为父类类型,里面的元素为子类类型
/*
Student,Teacher继承Person
stu为Student特有方法
tea为Teacher特有方法
*/
Person[] p = new Person[5];
p[0] = new Student("张三",18,69.5);
p[1] = new Student("李四",18,78.9);
p[2] = new Teacher("Tom",36,8000);
p[3] = new Teacher("Jary",40,6000);
p[4] = new Person("王五",36);
//输出
for(int i = 0;i < p.length;i++){
System.out.println(p[i].say());
}
//输出其特有方法
for(int i = 0;i < p.length;i++) {
if(p[i] instanceof Student){
Student s = (Student)p[i];
s.stu();
}else if(p[i] instanceof Teacher){
Teacher t = (Teacher)p[i];
t.tea();
}else if(p[i] instanceof Person){
}else{
System.out.println("错误❌");
}
}
7.6多态参数
方法定义的形参类型为父类,实参类型为子类
/*
Common,Manager继承Employee
Employee有getAnnual方法,输出一年工资
Common,Manager重写getAnnual方法
work为Common特有方法
manage为Manager特有方法
*/
public class test {
public static void main(String[] args) {
Employee e = new Employee();
Common c = new Common("张三",2000);
Manager m = new Manager("李四",5000,1000);
test t = new test();
//多态参数
t.showEmpAnnual(c);//传入子类,向上转型
t.testWork(c);//传入子类,向上转型
}
public void showEmpAnnual(Employee e){//父类
System.out.println(e.getAnnual());
}
public void testWork(Employee e){//父类
if(e instanceof Common){
((Common) e).work();//向下转型,调用子类特有类
}else if(e instanceof Manager){
((Manager) e).manage();
}
}
}
8.Object类
8.1equals方法
==是比较运算符,可以判断基本类型,引用类型
基本类型:判断值是否相等
引用类型:判断地址是否相等,即判定是否为同一个对象
A a = new A();
A b = a;
A c = b;
System.out.println(a == c);//true
B obj = a;//父类的引用指向子类的对象
System.out.println(obj == c);//true
class A extends B{}
public class B{}
equals:Object类中的方法,只能判断引用类型
默认判断是地址是否相等,子类中往往重写该方法,用于判断内容是否相等
Integer integer1 = new Integer(10000);
Integer integer2 = new Integer(10000);
System.out.println(integer1 == integer2);//flase
//不是同一个对象
System.out.println(integer1.equals(integer2));//true
//默认判断是地址是否相等,子类中往往重写该方法,用于判断内容是否相等
8.2自己重写equals方法
import java.util.*;
/*
判断两个Person对象的内容是否相等
如果两个Person对象的各个属性值相同,返回true
否则返回flase
*/
public class t4子类重写equals方法 {
public static void main(String[] args) {
Person2 p01 = new Person2("张三",18,'男');
Person2 p02 = new Person2("张三",18,'男');
System.out.println(p01.equals(p02));
}
}
class Person2{
private String name;
private int age;
private char gender;//gender表示性别
Person2(String name,int age,char gender){
this.name = name;
this.age = age;
this.gender = gender;
}
public boolean equals(Object obj){
if(this == obj){
//当前和传入相等
return true;
}
if(obj instanceof Person2){
//传入的对象是否为Person2类
Person2 p03 = (Person2)obj;
//向下转型,要得到传入类的属性
return this.name.equals(p03.name) && this.age == p03.age && this.gender == p03.gender;
}
//如果不是Person2类,直接返回false
return false;
}
public String getName(){
return name;
}
public void setName(){
this.name = name;
}
public int getAge(){
return age;
}
public void setAge(){
this.age = age;
}
public char getGender(){
return gender;
}
public void setGender(){
this.gender = gender;
}
}
8.3hashCode方法
1.提高具有哈希容器的效率
2.两个引用,指向同一个对象,哈希值肯定一样,指向不同对象,哈希值是不同的
3.哈希值主要根据地址号来的,不能完全将哈希值等价于地址
4.在集合中,hashCode如果需要,也会重写
A a1 = new A();
A a2 = new A();
A a3 = a1;
System.out.println(a1.hashCode());
System.out.println(a2.hashCode());
System.out.println(a3.hashCode());
//a1和a3是一样的
class A{}
8.4toString方法
默认返回全类名 + @ + 哈希值的十六进制
子类往往会重写toString方法,用于返回对象的属性信息
//Object的toString原码
public String toString(){
return getClass().getName() + '@' + Integer.toHexString(hashCode());
//getClass().getName()表示全类名,包名+类名
//Integer.toHexString(hashCode());将对象的hashCode值转成十六进制字符串
}
A a = new A("Tom",18);
System.out.println(a.toString());
//由于A类中没有重写,所以调用的是Object类中的toString方法
//重写toString方法,用于返回对象的属性信息
//alt + insert → toString
public String toString(){
return "对象的属性信息";
}
当直接输出一个对象时,toString方法会被默认调用
System.out.println(person);
//默认调用person.toString()
8.5finalize方法
1.当方法被回收时,系统自动调用该对象的finalize方法,子类可以重写该方法,做一些释放资源的操作
2.当某个对象没有任何引用时,就会被回收,在销毁该对象前,会先调用finalize方法
3.垃圾回收机制的调用,是由系统自己来决定的,也可以通过System.cg();主动触发垃圾回收机制
A a = new A(10);
a = null;
//这时A对象就是一个垃圾
System.cg();
//主动调用垃圾回收器
System.out.println("输出...");//先输出
/*
输出...
完成...
*/
class A{
private int age;
A(int age){
this.age = age;
}
public void finalize() throws Throwable{
System.out.println("完成...");
}
}
9.断点调试(debug)
以对象的运行类型来执行
1.F7: 跳入方法内
2.F8: 跳过,逐行执行代码
3.shift + F8: 跳出方法
4.F9: 执行到下一个断点
查看jdk源码