这部分是理解重点

IDEA快捷键

删除当前行ctrl+d;复制当前行ctrl+alt+向下箭头;补全代码alt + /;

添加或者取消注释ctrl+/;自动格式化ctrl+alt+L;运行快捷键alt +R;

自动生成构造器alt+insert;查看类的继承关系ctrl+H;ctrl+B跳转到某个类/方法的定义位置;

模板

maina模板等于public static void main(String[] args) {}

sout模板等于System.out.println();

fori模板等于for (int i = 0; i < ; i++) {}

作用:区分相同名字的类,管理类,控制访问范围

实际就是创建文件夹/目录保存类文件;

package com.hspedu;  //com.hspedu表示包名,package关键字打包
//idea中右键新建package->com.xiaoming和com.use
package com.use;           //声明当前Test类在com.use包(写在最上面)
import com.xiaoqiang.Dog;  //在package下面,类定义上面
public class Test{
		public static void main(String[] args) {
				Dog d1 = new Dog;  //调用xiaoqiang包里的Dog类
		}
}


//常用的包
java.util.*   //工具包,如java.util.Scanner
//引入包
import java.util.Scanner;  //只引入 java.util包下面的一个类
import java.util.*;        //导入包下的所有类
import java.util.Arrays;
//使用
Arrays.sort(arr);

包的命名:com.项目名.业务模块名

访问修饰符

用于控制方法(成员方法),属性(成员变量)和类的访问权限

只有public和默认能修饰类

面向对象的三大特征:封装、继承、多态

**封装**

把抽象出的数据(属性)和对数据的操作(方法)封装在一起,数据被保护在内部,只有被授权的方法才能用;

作用:隐藏实现的细节,可以对数据进行验证;

封装的实现步骤

1、将属性私有化private;

2、提供一个公共(public)的set方法,用于对属性判断并赋值;

3、提供一个公共(public)的get方法,用于获取属性的值; 

//封装案例
package com.encap;

public class encapsulation01 {
    public static void main(String[] args) {
        Person p1 = new Person();
        p1.setName("jack");
        p1.setAge(10);
        p1.setSalary(3000);
        System.out.println(p1.info());
        Person p2 = new Person("smith",80,9000);
        System.out.println(p2.info());
    }
}
class Person{
    public String name;
    private int age;      //私有化-main里不能直接赋值
    private double salary;

    public Person() {
    }
    public Person(String name, int age, double salary) {
        setName(name);
        setAge(age);
        setSalary(salary);
    }

    //快捷键alt+insert的getter and setter
    //用于对属性判断并赋值and获取属性的值
    public String getName() {
        return name;
    }
    public void setName(String name) {
        if(name.length() >= 2 && name.length() <= 6){
            this.name = name;
        }else{
            System.out.println("名字长度不符");
            this.name = "noname";
        }
    }
    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 = 18; //给默认年龄
        }
    }
    public double getSalary() {
        //可以增加权限判断
        return salary;
    }
    public void setSalary(double salary) {
        this.salary = salary;
    }
    public String info(){
        return "信息为 name=" + name + " age=" +
                age + " salary=" + salary;
    }
}

**继承**

代码复用性——当多个类存在相同的属性和方法时,可以抽象出父类定义相同的属性和方法,子类通过extends来声明继承父类即可。

  

父类的私有属性和方法不能在子类直接访问,但父类可以提供一个public方法间接访问;

public class extends01 {
    public static void main(String[] args) {
        pupil p1 = new pupil();
        //先调父类构造器student(),再调子类pupil()
        p1.age = 10;
        p1.name = "p1"; //score不能直接赋值,是私有的
        p1.testing();
        p1.setScore(99); //公共方法访问
        p1.showInfo();

        graduate g1 = new graduate();
        g1.age = 23;
        g1.name = "g1";
        g1.testing();
        g1.setScore(66);
        g1.showInfo();
    }
}

//父类,是graduate的父类
public class student {
    //共有属性
    public String name;
    public int age;
    private double score;
    private int n;
    //构造器
    public student() {
    }
    //共有方法
    public void setScore(double score) {
        this.score = score;
    }
    public int getN() {
        return n;
    }
    public void showInfo(){
        System.out.println("学生名" + name +
                " 年龄" + age + " 成绩" + score);
    }
}

//子类
public class graduate extends student{
    public void testing(){
        System.out.println("大学生" + name
                + " 正在考大学数学");
    }
}

子类必须调用父类的构造器,完成父类的初始化;

创建子类对象时,默认先去调父类的无参构造器,如果没有,需要在子类构造器中用super去指定父类构造器完成初始化,子类哪个构造器均可;(父类写的是有参构造器时,子类构造器需要写super(”tom”, 10);)

//假设父类有多个构造器
public sub(){
		super();            //表示父类的无参构造器被调用(不写默认调用)
		super("jack");      //表示调用父类一个参数的构造器
		super("jack", 10);  //表示调用父类两个参数的构造器
		System.out.println("子类sub()构造器被调用");
}

super在使用时,必须放在构造器的第一行(super只能在构造器中使用)

super()和this()两种调用方法都只能放在构造器第一行(不共存)

所有类都是Object的子类,构造器的调用一直向上追溯到Object类

子类最多只能继承一个父类

继承的本质

public class extends02 {
    public static void main(String[] args) {
		    son son = new son();
		    //按照查找关系来返回信息
		    System.out.println(son.name);     //大头儿子
		    System.out.println(son.age);      //报错private
		    System.out.println(son.getAge()); //39
		    System.out.println(son.hobby);    //旅游
    }
}
class grandpa{ //父类
		String name = "大头爷爷";
		String hobby = "旅游";
		int age = 80;
}
class father extends grandpa{
		String name = "大头爸爸";
		private int age = 39;
		public int getAge(){
				return age;
		}
}
class son extends father{
		String name = "大头儿子";
}

查找关系(1)子类有该属性且可以访问,则返回信息;

(2)子类没有这个属性,就向上查找直到Object返回信息;

super关键字

用于访问父类的属性,方法和构造器

private私有的属性和方法访问不了,访问构造器只能放在第一行;

public void sum(){
		System.out.println("子类的sum()方法");
		//调用父类cal方法的几种方法
		cal(); //首先找本类,没有则逐级向上找,找到但不能访问会报错
		this.cal();   //同上
		super.cal();  //直接从父类向上找
}

方法重写/覆盖

子类有一个方法和父类的某个方法的名称,返回类型和形参列表一样,就说子类sub的A方法重写了父类base的A方法;

返回类型一样,或父类的返回类型是子类返回类型的父类;

Object是String的父类(反过来写会报错)

子类方法不能缩小父类方法的访问权限public>protected>默认>private

**多态**

方法或对象具有多种形态,建立在封装和继承基础上;

方法的重写体现多态(不同对象调用到不同say方法)

多态的前提是:两个对象(类)存在继承关系

//对象的多态
//(1)一个对象的编译类型和运行类型可以不一致
//(2)编译类型在定义对象时就确定了不能改变,而运行类型可以改变
public class Test {
    public static void main(String[] args) {
    //编译类型Animal,运行类型Dog,可以父类的引用指向子类的对象
        Animal a = new Dog(); 
        Animal b = new Cat();
        a.say();   // 汪汪
        b.say();   // 喵喵
        a = new Cat(); //运行类型可以改变(a是引用不是对象)
    }
}
class Animal {
    public void say() {}
    public void eat() {}
}
class Dog extends Animal {
    public void say() {
        System.out.println("汪汪");
    }
    public void dogsay(){}
}
class Cat extends Animal {
    public void say() {
        System.out.println("喵喵");
    }
}

多态的向上转型

父类的引用指向子类的对象

父类类型 引用名 = new 子类类型();

//编译类型Animal,运行类型Dog
Animal a = new Dog();
a.eat();
a.say();
//可以调用父类的所有成员(属性和方法)(遵循访问权限)
//不可以调用子类特有的成员(属性和方法)
//最终的运行结果按照子类的实现(运行类型)

多态的向下转型

子类类型 引用名 = (子类类型)父类引用;

只能强转父类的引用a,不能强转父类的对象;

Animal a = new Dog(); //向上转型
//编译类型Dog,运行类型Dog
Dog b = (Dog) a;  //向下转型
b.dogsay();       //此时可以调用子类所有的成员(包括特有的)

//父类的引用必须指向当前当前目标类型的对象
Animal animal = new Cat(); 
Cat cat = (Cat) animal;  //可以
Dog dog = (Dog) animal;  //不可以,报错

属性没有重写,属性的值直接看编译类型

instanceof 比较操作符,判断对象的运类型是否为XX类型或XX类型的子类型;

public class Test {
    public static void main(String[] args{
		    Base base = new Sub();
		    System.out.println(base.count); //编译类型,输出10
		    
		    Base base1 = new Sub();
		    System.out.println(base1 instanceof Sub);  //true
		    System.out.println(base1 instanceof Base); //true
    }
}
class Base{
		int count = 10;
}
class Sub extends Base{
		int count = 20;
}

java的动态绑定机制

当调用对象方法时,该方法会和该对象的内存地址/运行类型绑定;

当调用对象属性时,没有动态绑定机制,哪里声明哪里使用;

public class dynamicBind {
    public void main(String[] args) {
        A a = new B(); //a的编译类型A,运行类型B
        //先找子类的方法再向上找父类的sum方法,此时getI()调哪个?
        //动态绑定机制:调方法会和运行类型绑定,getI()用子类的
        System.out.println(a.sum());  //20+10
        //属性不绑定,直接用父类的i
        System.out.println(a.sum1()); //10+10
    }
}
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 getI(){
        return i;
    }
}

多态数组

数组的定义类型为父类类型,里面保存的实际元素类型为子类类型;

//Person是父类,其子类是Student和Teacher
Person[] persons = new Person[5]; //创建父类引用数组
persons[0] = new Person("jack", 20);
persons[1] = new Student("tom", 18, 60);
persons[2] = new Student("amy", 22, 80);
persons[3] = new Teacher("smith", 35, 2000);
persons[4] = new Teacher("amy", 45, 4000);
//共有方法调用
for (int i = 0; i < persons.length; i++){
		//动态访问机制,编译类型一直是Person
		System.out.println(persons[i].say()); //访问每个类的say()方法
		//特有方法调用
		if(persons[i] instanceof Student){
				Student stu = (Student)persons[i]; //向下转型
				stu.study();
		}else if(persons[i] instanceof Teather){
				Teather tec = (Teather)persons[i]; //向下转型
				tec.teach();
		}else if(persons[i] instanceof Person){}
}

多态参数:方法定义的形参是父类,实参允许为子类

Object类

所有类的父类,其方法都可以用,几个常用方法如下:

//equals方法(只能由引用类型调用)
"hello".equals("abc"); //false
String str1 = new String("abc");
String str2 = new String("abc");
System.out.println( str1 == str2);  //false地址不同
System.out.println( str1.equals(str2)); //true值相同
/*题目:==和equals的对比
==可以判断基本类型值是否相等,引用类型的地址是否相等(是否同一对象)
equals只能由引用类型调用,默认是比较地址是否相等,
而子类往往会重写该方法,如Integer和String重写为判断值是否相等
*/
//Doctor类(name,age属性)重写equals方法
@Override
public boolean equals(Object obj){
		if(this == obj){
				return true;
		}
		if(!(obj instanceof Doctor)){
				return false;
		}
		Doctor d = (Doctor)obj;
		return this.age == d.age &&
				(name == null ? d.name == null : name.equals(d.name));
}

去 JDK 的源码里看某个类 / 方法的实现 ctrl+b

//hashCode方法(返回对象的哈希码值)
//两个引用指向同一个对象,则哈希值肯定是一样的(基于地址得到)

//toString方法(返回对象的字符串表示)
//默认返回:全类名(包名+类名) + @ + 哈希值的十六进制
//重写方法toString()-可以用于打印对象/拼接对象alt+insert
//直接输出对象,默认等价加上.toString()
@Override
public String toString(){ //重写打印对象的属性
    return "Person{" +
        "name='" + name + '\'' +
        ", age=" + age +
        ", job='" + job + '\'' +
        '}';
}
//finalize方法(当对象被回收前,系统自动调用该对象的finalize方法)
//对象没有引用时,垃圾回收器会回收/销毁对象
//子类可以重写这个方法-释放资源的操作alt+insert

断点调试Debug

断点调试时,是运行状态,按对象的运行类型来执行

F7跳入;F8跳过;shift+F8跳出;F9resume执行到下个断点

F8逐行执行代码,跳过方法内部;

F7可以追踪方法的源码;

退出方法写return;

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐