此文章是基础语法的后续。进阶中级
文章目录
前言
以下是本篇文章正文内容,下面案例可供参考
1.IDEA快捷键
ctrl+D删除光标当前行
ctrl+alt+向下光标复制光标当前行
alt+/ 补全代码
自动导入该行需要的类:首先需要打开setting--Editor---General---Auto import,把所属java的框框打勾。可以使用Alt+enter
快速格式化代码:ctrl+alt+L
快速运行程序:alt+R(自己设定)
生成构造器:alt+insert
查看一个类的层级关系ctrl+H
将光标放一个方法上,输入ctrl+B可以定位到方法(学到继承有用)
自动分配生成变量名,(在后面加.var)
模板快捷键 main模板、sout模板、fori模板,然后回车
包基本语法:package com.hspedu表示包名
包名命名规则:只能包含字母、数字、下划线、小圆点,不能数字开头不能是关键字和保留字
一般命名以com.公司名.项目名.业务模块名
package的作用是申明当前类所在包,需要放在最上面,一个类最多只有一句package
,导入其他包放它下面
常用包:
java.lang.*基本包,不需要导入
java.util.* 系统提供工具包如Scanner
java.net.* 网络包
java.awt.* java界面开发GUI
2.访问修饰符
public:对所有公开
protected:对子类、本类或同一个包的类公开
默认级别:没有修饰符,向同一个包、本类公开,不对子类公开
私有级别:private只有本类里面可以访问,不对外公开。
修饰类只有默认和public可以修饰类
3.面向对象编程(封装、继承、多态)
3.1封装encapsulation
封装就是把抽象出的数据(属性)和对数据的操作(方法)封装在一起,数据被保护在内部,程序的其他部分只有通过授权的操作(方法)。才能对数据操作。
封装实现步骤:1.将属性私有化【不能直接修改属性】
2.提供一个公共的方法set,用于对属性判断和赋值public void setXxx(类型 参数名)
3.提供一个公共的get方法用于获取属性值 public XX get()
快速获得get、set方法
get、set方法与构造器混和使用保护机制仍然存在,
package com.xiaoming;
public class Person {
public static void main(String[] args)
{
ZZZ z=new ZZZ("lala",20,3000,"数据的");
z.setName("sdasd");
z.setAge(52);
z.setSalary(2000);
System.out.println(z.info());
}
}
class ZZZ
{
public String name;
private int age;
private int salary;
private String job;
public ZZZ(String name, int age, int salary, String job) {
setSalary(salary);//这样构造器执行set方法仍然有保护机制
this.setAge(age);
setName(name);
setJob(job);
}
public String getName() {
return name;
}
public void setName(String name) {
if(name.length()>6)
{
System.out.println("不合理名字");
}
else
{
this.name = name;
}
}
public int getAge() {
return age;
}
public void setAge(int age) {
if(age>=1&&age<=120)
{
this.age = age;
}
else
{
System.out.println("不合理");
this.age=18;//默认年纪
}
}
public int getSalary() {
//可以增加权限访问
return salary;
}
public void setSalary(int salary) {
this.salary = salary;
}
public String getJob() {
return job;
}
public void setJob(String job) {
this.job = job;
}
public String info()
{
return "返回信息为"+name+"年龄"+age+"工资"+salary;
}
}
3.2继承Extends
解决代码复用性,当多个类存在相同属性和方法,可以从这些类抽象出父类,在父类中定义的属性和方法,所有子类不需要重新定义,只需要通过extends声明继承父类即可。
class 子类 extends 父类,子类会自动拥有父类定义的属性和方法(就是因为super作用)
public class Students {//父类
public String name;
public int age;
public double score;
public void setScore(double score) {
this.score = score;
}
public void show()
{
System.out.println("学生名字"+name+" 年纪"+age+" 分数"+score);
}
}
public class pupil extends Students {//继承
public void testing()
{
System.out.println("正在考试"+name);
}
}
继承细节:
1.子类继承父类所有属性方法。但是父类私有(private)属性和私有方法不可以直接访问。可以通过父类提供的公共方法得到(通过返回值方式获得私有属性,或者父类公共方法调用私有方法)
2.子类必须调用父类构造器,完成父类初始化,在创建子类对象时,不管使用子类哪一个构造器,默认情况下都会调用父类无参构造器,若父类没有无参构造器则必须在子类的构造器用super指定使用父类的哪一个构造器完成父类属性初始化工作。否则编译不通过。
注意:子类和父类还不是一个对象,只是子类有父类属性和方法。
3.指定调用父类某个构造器,直接显示调用 super(构造器形参参数)
4.super调用构造器时使用,必须放在子类构造器第一行,只能在构造器中使用。
5.super()与this()都必须放在构造器里的第一行,因此这两个方法不可以同时存在一个构造器中
6.Object类是java所有类的父类,而且父类构造器被调用不仅仅局限于直接父类,会一直追溯到Object类。(father类构造器随着new son()被调用,father的父类Object构造器也会被调用)
7.子类只能继承一个父类,java是单继承机制
8.不能滥用继承,子类和父类之间必须满足is-a逻辑关系
//父类
public class father {
public String name="lal";
protected String work="工人";
private int age=18;
public father() {
System.out.println("父类无参构造物被调用");
}
public father(String name, String work, int age) {
this.name = name;
this.work = work;
this.age = age;
System.out.println("新father父类有参构造物被调用");
}
public void getwork()
{
System.out.println("这人工作是"+work);
}
public void getage()
{
System.out.println("这人年纪是"+age);
}
}
//子类
public class son extends father{
public son()
{
//super();//默认调用父类无参构造器
super("smith","白领",10);//调用另一个父类有参构造器,在没有无参构造器必须申明
System.out.println("子类无参构造");
}
public void speak()//子类方法
{
System.out.println("我爸的名字是"+name+work);
getwork();
getage();
}
}
//测试
public class test {
public static void main(String[] args)
{
son s=new son();
s.speak();
}
}
继承本质:当子类继承父类,创建子类对象时,先加载类信息、在堆里分配对象空间并指向常量区一些参数。栈里生成对象名。查找规则:先看子类是否有该属性,有并且可以访问返回该信息,若不能访问可以使用公共方法,如果子类没有就向上一级父类查找(从子向父查)。
注意:若子类属性是private,而父类是public,也不可以访问到父类的,被子类private“卡住”,只能通过公共方法获得子类属性
public class ExtensTheory {
public static void main(String[] args)
{
son s=new son();
System.out.println(s.age);
System.out.println(s.name);
System.out.println(s.hobby);
}
}
class Grandpa
{
String name="大头爷爷";
String hobby="旅游";
}
class Father extends Grandpa
{
String name="大头爸爸";
int age=39;
}
class son extends Father
{
String name="大头儿子";
}
继承super练习题
package com.extendss;
import java.awt.*;
public class ExtendsExercise{
public static void main(String[] args)
{
PC pc=new PC("i5",100,1500,"联想");
pc.printinfo();
Notepad pad=new Notepad("ios15",100,500,"red");
pad.printinfo();
}
}
class Computer
{
private String CPU;
private int memory;
private int disk;
public Computer(String CPU, int memory, int disk) {//构造器
this.CPU = CPU;
this.memory = memory;
this.disk = disk;
}
public String getDetail()
{
return "电脑cpu是"+CPU+" 内存是:"+memory+" 硬盘是:"+disk;
}
}
class PC extends Computer//默认调用父类无参构造器但是父类没有无参,必须用super指定
{
private String broad;
public PC(String CPU, int memory, int disk, String broad) {//父类构造器通过super(参数)完成父类属性初始化,
super(CPU, memory, disk);//PC里也可以没有这三个父类参数,直接在super指定值,因为父类构造器有三个参数。
this.broad = broad;
}
public String getBroad() {
return broad;
}
public void setBroad(String broad) {
this.broad = broad;
}
public void printinfo()
{
System.out.println("电脑信息是 "+getDetail()+" "+getBroad());
System.out.println();
}
}
class Notepad extends Computer
{
private String color;
public Notepad(String CPU, int memory, int disk, String color) {
super(CPU, memory, disk);
this.color = color;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public void printinfo()
{
System.out.println("pad信息是"+getDetail()+" "+getColor());
}
}
3.3super用法
super代表父类引用,用于访问父类方法、属性、构造器,但是不能访问父类private的属性和方法。找方法会从本类找,有则调用,否则向上父类依次寻找,若方法存在不可以访问,报错,若没找到,显示方法不存在
访问父类构造器必须在自己构造器使用调用。如下演示
public class A {
public int n1=100;
protected int n2=200;
int n3=300;
private int n4=400;
public A()
{
System.out.println("调用A默认无参构造器");
}
public A(int n1, int n2, int n3,int n4) {
this.n1 = n1;
this.n2 = n2;
this.n3 = n3;
this.n4=n4;
}
public void test100(){
System.out.println("调用Atest100");
}
protected void test200(){
System.out.println("调用Atest200");
}
void test300(){
System.out.println("调用Atest300");
}
private void test400(){
System.out.println("调用Atest400");
}
}
public class B extends A {
public B()
{
super(400,500,600,700);//构造器可以访问私有属性
System.out.println("调用B默认无参构造器");
}
public void hi()
{
System.out.println(super.n1+""+super.n2+""+super.n3);
super.test100();
super.test200();
super.test300();
}
}
调用父类构造器的好处在于分工明确,父类属性由super父类构造器初始化,子类属性由子类构造器初始化。
注意:在有继承关系的A,B类
找方法会从本类找,有则调用,否则向上父类依次寻找,若方法存在不可以访问,报错,若没找到,显示方法不存在。
在子类里this.方法()与方法() 一样作用,都会先从本类找再去父类爷爷类找
而是super.方法()。是直接去查找父类或者爷爷类找方法。不查找本类!! (查找属性也是一样)
super的访问不仅仅局限于直接父类,如果条件允许,可以访问爷爷类中同名属性或者方法(查找遵循就近原则,先子再父。也要遵循访问权限相关规则)
3.4方法重写、覆盖Override
在继承关系中,方法覆盖就是子类方法与父类方法的某一个方法名称、形参参数也要一样、返回类型完全一样。那么子类就是覆盖了父类的方法(这里不仅仅局限于子类与父类,爷爷也是。子与爷覆盖)
方法重写细节:
子类的返回类型和父类的返回类型一样或者是父类返回类型的子类,也可以是方法重写
比如:父类返回类型是Object,子类返回类型是String。其他参数一样。那么这两个也是方法重载(Object是java所有类的父类)
在方法重写时,子类方法权限修饰符不可以比父类方法的访问权限还小,只能比父类大,在其他都一样的情况下可以构成方法重写
public class A {
}
public class B extends A{
}
public class Animal {
public void cry()
{
System.out.println("Animals方法");
}
public Object getinfo()//Object是所有类的父类
{
return null;
}
public A get()//B是A子类
{
return null;
}
protected void gets()//父类方法访问权限小
{
System.out.println("Animals的gets方法");
}
}
public class Dog extends Animal {
public void cry()
{
System.out.println("Dog方法");
}
public String getinfo()
{
return "Dog方法的getinfo";
}
public B getB()
{
return null;
}
public void gets()//子类访问权限比父类大
{
System.out.println("Dog的gets方法");
}
}
3.5多态polymorphic
方法或对象具有多种形态,多态是建立在封装和继承之上的。重写与重载体现多态
对象的多态:1.一个对象的编译类型和运行类型可以不一致。例如Animal animal=new Dog():编译类型是animal,运行类型是Dog
2.编译类型在定义对象时就确定了,不可以改变
3.运行类型是可以改变的
4.编译类型看定义时=号左边,运行类型看=号右边 animal=new Cat()运行类型转为Cat,编译不变。
方法的执行主要是看运行类型,运行类型是什么,就执行哪个类的方法
public class Animal {
public Animal()
{
System.out.println("Animals类");
}
public void cry()
{
System.out.println("动物在叫");
}
}
public class Dog extends Animal{
public Dog()
{
System.out.println("Dog类");
}
public void cry() {
System.out.println("cat cry()小狗叫");
}
}
public class Cat extends Animal {
public Cat()
{
System.out.println("猫类");
}
public void cry() {
System.out.println("cat cry()小猫叫");
}
}
public class PolyObject {
public static void main(String[] args)
{
Animal animal=new Dog();//animal是编译类型,Dog是运行类型,先编译在运行,先执行animal构造方法再执行Dog
animal.cry();//执行到该行时,运行类型是Dog,所以是以Dog的cry
animal=new Cat();//编译类型还是animal,运行类型时Cat
animal.cry();
}
}
多态的前提是:两个对象或者类是存在继承关系
多态的向上转型:父类引用指向子类对象 ----> 父类类型 引用名=new 子类类型()
Object obj=new Cat()也可以。一切类都是Object子类。Object也是Cat父类
在定义方法时,形参时父类类型引用名,而在调用方法时实参是具体子类引用名
obj可以调用父类中所有成员(注意访问权限),因为在编译阶段能调用哪些成员是由编译类型决定。
不可以调用子类特有成员(允许子类没有父类有,会调用父类,但是父类没有子类有的不能调用)
最终运行效果看运行类型,先从子类,看子类具体实现,若子类没有去父类找方法
public class Animal {
private String name;
public Animal(String name)
{
this.name=name;
System.out.println("Animal构造器");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public class Dog extends Animal {
public Dog(String name)
{
super(name);
}
}
public class Cat extends Animal {
public Cat(String name)
{
super(name);
}
}
public class Food {
private String name;
public Food(String name) {
this.name = name;
System.out.println("Food构造器");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public class Fish extends Food{
public Fish(String name)
{
super(name);
}
}
public class Bone extends Food {
public Bone(String name)
{
super(name);
}
}
public class Master {
private String name;
public Master(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void feed(Animal animal,Food food)//这里其实是涉及到动态绑定
{
System.out.println("主人名字"+name+" 给"+animal.getName()+" 吃"+food.getName());
}
}
public class Poly01 {
public static void main(String[] args)
{
Master master=new Master("汤姆");
Dog dog=new Dog("小黑");
Bone bone=new Bone("骨头");
Cat cat=new Cat("小花");
Fish fish=new Fish("小鱼");
master.feed(dog,bone);//这里做的工作就相当于Animal animal=new Dog()==Dog dog
master.feed(cat,fish);
}
}
anminal编译类型是Animal,可以接收Animal子类的对象,然后以子类对象为运行类型,执行操作
多态的向下转型:(他的出现就是为了解决向上转型中不可以调用子类特有成员)
语法:子类类型 子类引用名=(子类类型) 父类引用名
只能强转父类引用,不可以强转父类对象
要求父类的引用必须指向的是当前目标类型的对象(前面要有这句话Animal animal=new Cat(),animal才是指向Cat对象)
可以调用子类类型所有的成员
public class Animal {
private String name;
public Animal(String name)
{
this.name=name;
System.out.println("Animal构造器");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void sleep()
{
System.out.println("睡");
}
public void run()
{
System.out.println("跑");
}
}
public class Cat extends Animal {
public Cat(String name)
{
super(name);
}
public void sleep()//重写
{
System.out.println("小猫睡");
}
public void catchMouse()
{
System.out.println("猫抓老鼠");
}
}
public class PolyDetail {
public static void main(String[] args)
{
Animal animal=new Cat("小黑");
animal.sleep();//向上转型
animal.run();
((Cat) animal).catchMouse();//(向下转型)把animal强转为子类类型,然后调用子类特有方法
}
}
多态注意事项:属性没有重写的说法,属性的值看编译类型(左边),方法的值看运行类型右边
public class PolyDetail2 {
public static void main(String[] args)
{
Base base=new Sub();//向上转型
System.out.println(base.count);//20,属性的值看编译类型(左边)看编译类型
Sub sub=(Sub)base;//向下转型
System.out.println(sub.count);//30
}
}
class Base
{
int count=20;
}
class Sub extends Base
{
int count=30;
}
instanceOf比较操作符,用于判断对象的运行类型是否是XX类型或者是否是XX类型的子类型
多态练习题:
4.动态绑定机制DynamicBinding
当调用对象方法时,该方法会和该对象的内存地址/运行类型绑定
当调用属性时,没有动态绑定机制,哪里有申明属性那里就使用那个
动态绑定的经典应用是在于:在某一个方法里形参是父类引用,而在调用方法时,将一个子的引用传递给形参,(这里做到了向上转型)而这样实现了动态绑定,运行类型就是子类了,如同上面此方法public void feed(Animal animal,Food food),调用此方法时传入的是子类的 Cat cat= new Cat()的cat,而cat就是new Cat(),也就做了向上转型
5.多态数组(多态的应用)
public class Person {
private String name;
private int age;
public Person(String name,int age)
{
this.name=name;
this.age=age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String say()
{
return "姓名"+name+" 年纪"+age;
}
}
public class Student extends Person{
private int score;
public Student(String name,int age,int score)
{
super(name,age);
this.score=score;
}
public int getScore() {
return score;
}
public void setScore(int score) {
this.score = score;
}
public String say()
{
return super.say()+" 分数是"+score;//不仅仅重写say方法,也要用到父类say
}
public void study()
{
System.out.println("学生名字是:"+getName()+"正在学习"+" 考试分数是"+score);
}
}
public class Teacher extends Person{
private int salary;
public Teacher(String name,int age,int salary)
{
super(name,age);
this.salary=salary;
}
public int getSalary() {
return salary;
}
public void setSalary(int salary) {
this.salary = salary;
}
public String say()
{
return super.say()+" 薪水是"+salary;
}
public void teach()
{
System.out.println("老师名字是:"+getName()+"正在授课"+" 薪水是:"+salary);
}
}
public class PolyArr {
public static void main(String[] args)
{
//要求创建1个Person对象、2个Teacher、2个Student,统一放在数组里
//放在数组里,那么必须用父类来接收,父类引用可以指向子类对象
Person[] person=new Person[5];//对象数组:person可以放Person对象,同时也就可以放子类对象
person[0]=new Person("jack",20);//这里都是向上转型
person[1]=new Teacher("mike",18,10000);
person[2]=new Teacher("jone",22,13000);
person[3]=new Student("小黑",10,60);
person[4]=new Student("小明",8,70);
for(int i=0;i<person.length;i++)
{
//person[i]的编译类型是Person,运行类型是根据实际的上面运行类型,由JVM判断
System.out.println(person[i].say());//动态绑定机制
//这里也可以使用类型判断和向下转型结合
if(person[i] instanceof Student)
{
Student student=(Student)person[i];
student.study();
}
else if(person[i] instanceof Teacher)
{
Teacher teacher=(Teacher)person[i];
teacher.teach();
}
else if(person[i] instanceof Person){}
else
{
System.out.println("输入有误");
}
}
System.out.println("------------------");
//向下转型,调用Student、Teacher类特有方法
Student student1=(Student) person[3];
student1.study();
Student student2=(Student) person[4];
student2.study();
Teacher teacher1=(Teacher) person[1];
teacher1.teach();
Teacher teacher2=(Teacher) person[2];
teacher2.teach();
}
}
6.Object类详解
基本数据类型的比较只看值是否一样。
查看源码:将光标放方法上,然后ctrl+b或者右击方法--goto---Declaration
6.1equals方法重写:
public class EqualsExercise01 {
public static void main(String[] args)
{
Person1 p1=new Person1("jack",18,'男');
Person1 p2=new Person1("jack",18,'男');
//System.out.println(p1.equals(p2));//假,没有重写的equals只判断引用类型地址
System.out.println(p1.equals(p2));
}
}
class Person1
{
private String name;
private int age;
private char gender;
public Person1(String name, int age, char gender) {
this.name = name;
this.age = age;
this.gender = gender;
}
//重写Object类的euqals方法
public boolean equals(Object object)
{//如果比较的是同一个对象,返回ture
if(this==object)
{
return true;
}
else if(object instanceof Person1)
{//向下转型,因为需要子类的属性
Person1 p=(Person1)object;
return this.name.equals(p.name) && this.age==p.age && this.gender==p.gender;
}
return false;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public char getGender() {
return gender;
}
public void setGender(char gender) {
this.gender = gender;
}
}
6.2hashCode方法
hashCode()具有提高哈希结构容器的效率、两个引用,如果指向同一个对象,则哈希值肯定相同。哈希值是根据地址号来编写的,哈希值不完全等价于地址
6.3toString()方法
默认返回:全类名+@+哈希值的十六进制(查看Object类的toString())
重写toString()方法
public String toString() {
return "Person1{" +
"name='" + name + '\'' +
", age=" + age +
", gender=" + gender +
'}';
}
当直接输入一个对象时,toString()方法会被默认调用。比如System.out.println(person);就会自动调用person.toString()
6.4finalize()方法
当对象被回收时,系统自动调用对象的finalize(),子类可以重写该方法,做一些释放资源的操作。
什么时候被回收,当某个对象没有任何引用时,jvm就认为这个对象是一个垃圾对象,会使用垃圾回收机制销毁对象,在销毁对象前,会调用finalize()。垃圾回收机制时系统决定的,也可以通过System.gc()主动触发垃圾回收机制
若不重写finalize,那么会调用Object类的finalize,默认处理
若重写finalize,就可以实现自己的逻辑——直接输入finalize会有提示
一般实际工作不会使用
@Override
protected void finalize() throws Throwable {
System.out.println("销毁对象");
}
7断点调试Debug
提示:在断点调试过程中,是运行状态,是对象的运行类型来执行的.
程序运行到断点会停止,然后一步一步往下调试。调试过程中,可以看到各个变量的值,出错的话,调试到出错代码会显示错误。分析找出bug
F5(跳入方法内)、Alt+Shift+F7强制进入方法内、F6逐行执行、F7跳出方法、F8执行到下一个断点
将光标放在变量上,会显示最新数据,
断点可以在Debug过程中,动态下断点,
下断点位置是没有执行到的。
总结
以上就是Java中级语法要讲的内容,中级部分实践项目另写一篇。后续将写java高级部分