1 零散知识点
1.1冒泡排序的思想以及核心代码体现
冒泡思想:
两两比较,将大的值放后放置,第一次比较完毕,最大值处在最大索引处;依次比较,可以得排好序的组;
比较的次数:数组长度-1次
第一次:有0个不比
第二次:有1个不比
....
for(int x = 0 ;x < arr.length-1; x++){ //外层循环确定比较次数
for(int y = 0 ; y < arr.length-1-x ;y++){ //内层循环确定交换次数
if(arr[y] > arr[y+1]){
int temp = arr[y] ;
arr[y] = arr[y+1] ;
arr[y+1] = temp ;
}
}
}
1.2方法的形式参数是基本数据类型和引用数据类型的区别
数据的类型分为:基本数据类型和引用数据类型。
如果是基本数据类型,形式参数的改变不会影响实际参数----特殊的引用类型String和这个效果一致!
如果是引用数据类型(除过String),形式参数的改变直接影响实际参数(实际参数需要传递空间地址值)
基本数据类型:不需要被jvm加载(校验语法格式-->编译时期)
引用数据类型:类,数组,接口----->class Student{} ---->被jvm加载 (需要编译---运行时期)
1.3构造方法
类的成员:成员变量、成员方法、构造方法
构造方法
1)方法名和类名一致
2)没有具体返回值类型
3)连void都没有
构造方法是可以重载!
构造方法的作用:
给类的成员进行数据初始化!
注意事项:
1)一个类中,如果没有任何构造方法,那么系统(jvm)自动会给我们提供无参构造方法!
2)一个类中,只提供有参构造方法,那么系统不会无参构造方法,此时,建议我们永远给出无参构造方法!否则,就出现问题!
创建对象的时候固定格式:
类名 对象名 = new 类名() ;
例题
class Student{//学生类
//带两个参数
private String name ;//姓名
private int age ; //年龄
/*
1)方法名和类名一致
2)没有具体返回值类型
3)连void都没有
*/
public Student(){
System.out.println("这是Student的无参构造方法") ;
}
//带有一个String类型的参数的构造方法
public Student(String name){ //姓名:局部变量---成员变量
System.out.println("这是一个带有String参数的构造方法") ;
this.name = name ;
}
//带有String类型,以及int类型的构造方法
public Student(String name,int age){ //构造方法能够重载
System.out.println("这是一个带两个参数的构造方法") ;
this.name=name ;
this.age = age ;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
}
//测试类
class ConstructorDemo{
public static void main(String[] args){
//创建一个学生类对象
Student s = new Student();
System.out.println(s) ;//堆内存地址
System.out.println("-------------------") ;
Student s2 = new Student("高圆圆") ;
System.out.println(s2) ;//新的堆内存空间
System.out.println("-------------------") ;
//在创建第三个学生对象
Student s3 = new Student("高圆圆",44) ;
System.out.println(s3) ;//新的堆内存空间
System.out.println("-------------------") ;
System.out.println(s3.getName()+"---"+s3.getAge());
}
}
结果:
![](https://i-blog.csdnimg.cn/blog_migrate/d6673c07cef0ddabf1e9f077ca237abc.png)
结构分析:构造方法是可以重载的,相同的方法名,不同的参数,会创建不同的空间地址值
1.4匿名对象
匿名对象: 没有名字的对象!
格式:
new 类名();
特点:
1)匿名对象使用一次即可,提高jvm的垃圾回收器的回收效率,使用完毕,被jvm的垃圾回收器 立即回收!
2)匿名对象直接在堆内存开辟空间
3)可以作为形式参数传递!
例题:
class Student{
public void study(){
System.out.println("正在学生JavaSe") ;
}
}
class StudentDemo{
public void method(Student s){//当形式参数是类时,需要创建当前学生类对象,形式参数
//就是此对象相当于传入Student类的空间地址值,然后用
//这个地址值去调用Student类中的方法,一种传递的思想
s.study() ;
}
}
//主测试类
public class Test{
public static void main(String[] args){
//需要访问StudentDemo类中的method方法?
//1)创建当期类具体对象
// StudentDemo sd = new StudentDemo() ;
//2)创建一个具体的学生对象
//Student student = new Student() ;
//sd.method(student) ;
//匿名对象的方式去书写(链式编程)
//链式编程:自己去使用可以,开发中一般上面写法
new StudentDemo().method(new Student());
}
}
结果:
![](https://i-blog.csdnimg.cn/blog_migrate/8be1064c3a86c6c12218d362f1b346ab.png)
1.5方法重写和方法重载的区别?
方法重写:override
继承体系中,子类继承父类,子类想沿用父类的功能,还是使用自己的功能,出现了和父类一模一样的方法(复写/重写/覆盖),在重写的时候,子类的方法的权限不能更低!
方法重载:overload
在定义的方法是,为了提供功能扩展性,同一个方法名,可以传递不同的参数!
方法名相同,参数列表不同,与返回值无关;
参数列表不同:
1)参数个数
2)参数类型
2)考虑参数顺序
1.6 this和super的区别?
概念上的区别
this:代表当前类对象的地址值引用
super:代表的父类的空间标识(父类对象的地址值引用)
访问成员变量的区别
this.变量名; 访问的本类中的成员变量
super.变量名; 访问的是父类成员变量
访问构造方法的区别
this(); 访问的是本类的无参构造方法
super() ;访问的父类的无参构造方法
this(xx) ; 访问的是本类的有参构造方法
super(xx) ;访问的是父类的有参构造方法
访问成员方法的区别:
this.方法名() ;访问本类的成员方法
super.方法名() ;访问的是父类的成员方法
1.7final关键字的特点
final关键字特点:(状态修饰符,最终的,无法更改的!)
final修饰类,该类不能被继承!
final修饰成员方法,该方法不能被重写
final修饰一个变量,此时变量一个常量;
编译时期常量:基本类型数据类型,jvm不需要加载
运行时期常量:引用数据类型,jvm需要加载
开发中,传统方式自定义常量
public final static 数据类型 变量名 = 初始化值;
1.8封装,继承,多态的含义
封装:
将一个事物(类)的属性私有化,对外提供公共的访问方法;属性私有化,外界类不能直接访问,但是可以通过公共的功能间接访问!
继承:
将多个事物(类)共性内容,抽取到一个独立的类中,这个类和这多个类产生一种关系"extends";
提高代码的复用性
提高代码的维护性
是多多态的前提条件
多态:
一个事物体现的不同形态--->内存中的变化
前提条件:
1)必须有继承关系
2)存在方法重写
3)父类引用指向子类对象 Fu fu = new Zi() ;
fu.方法名() ; 存在重写,编译看左,运行看右!
fu.变量名; 编译看左,运行看左;
1.9什么是接口,接口和抽象类的区别
接口:
体现事物的一种额外扩展功能,事物本身具备,这个事物只要实现了接口,就具备接口暴露的功能!
接口中的成员方法:只能是抽象方法,需要让子实现类全部必须实现;
接口和抽象类的区别:
成员的区别:
抽象类:
成员变量:可以为变量,也可以为自定义常量
构造方法:有参/无参构造方法都存在,目的为了给类的成员进行初始化,分层初始化
成员方法:即可以有抽象方法,也可以有非抽象方法
接口:
成员变量:只能是常量,存在默认的隐藏的修饰符 public final static
构造方法:没有
成员方法:只能是抽象方法
关系的区别:
类与类:继承关系,extends-->只支持单继承,不支持多继承,可以多层继承
类与接口:实现关系,implements-->一个类继承另一个类的同时,可以实现多个接口,接口名和接口名逗号隔开
接口与接口:继承关系,extends-->支持单继承,多继承,多层继承!
设计理念
抽象类:继承关系,体现核心思想"is a" 的关系,类A是类B的一种或者类B是类A的一种
接口:子实现类和接口实现关系----体现核心思想 "like a"的关系,是事物的额外的扩展功能!
1.10 final,finally,finalize的区别?
final:
状态修饰符,最终的,无法更改的;
修饰类,该类不能被继承
修饰变量,此时变量是一个常量
修饰成员方法,该方法不能被重写
finally:
Java语言中去处理代码中出现异常的一种格式:
1)捕获异常 try....catch....finally
2)抛出异常 在方法上面throws
try{
可能出现问题的代码
}catch(异常类名 对象名){
异常处理
}finally{
//释放系统资源
}
finalize:
是一个方法名,是Object类中定义的,它是和jvm中的垃圾回收器有关系
专门用来回收没有更多引用的对象,及时释放内存,节省空间!
1.11权限修饰符
/**
* 权限修饰符的范围
*
* 同一个包下的同一个类中 同一个包下的子类中/同一个包下的无关类中 不同包下的子类中 不同包下的无关类中
* private:私有 Y
* 默认修饰符 Y Y
* protected:受保护的 Y Y Y
* public:公共的/公开的 Y Y Y Y
*
*
*/
public class PermissionDemo {
public static void main(String[] args) {
PermissionDemo pd = new PermissionDemo() ;
pd.show() ;
pd.show2() ;
pd.show3() ;
pd.show4();
}
//私有
private void show(){
System.out.println("show PermissionDemo");
}
//默认修饰符
void show2(){
System.out.println("show2 PermissionDemo");
}
//受保护的
protected void show3(){
System.out.println("show3 PermissionDemo");
}
//公共的
public void show4(){
System.out.println("show4 PermissionDemo");
}
}
结果:
![](https://i-blog.csdnimg.cn/blog_migrate/48b829f012ea04e19ad189bffe08bd85.png)
/**
* PeermissionDemo的子类
*/
public class PermissionDemo2 extends PermissionDemo{
public static void main(String[] args) {
//创建子类对象
PermissionDemo2 pd2 = new PermissionDemo2() ;
// pd2.show() ; 私有用不了
pd2.show2() ; //默认修饰符
pd2.show3() ; //受保护的
pd2.show4() ;//公共的
}
}
/**
* 同一个包下的无关类中
*/
public class PermissionTest {
public static void main(String[] args) {
//创建PermissionDemo类对象
PermissionDemo pd = new PermissionDemo() ;
pd.show2() ;//默认修饰符
pd.show3(); //受保护的
pd.show4(); //公共开的
}
}
import com.qf.permission_03.PermissionDemo;
/**
* 不同包下的子类中
*/
public class PermissionDemo3 extends PermissionDemo {
public static void main(String[] args) {
//创建PermissionDemo3类对象
PermissionDemo3 pd3 = new PermissionDemo3() ;
// pd3.show2() ; //默认修饰符用不了
pd3.show3(); //受保护的
pd3.show4();
}
}
/**
* 不同包下的无关类中
*/
public class PermissionTest2 {
public static void main(String[] args) {
//创建PermissionDemo类对象
PermissionDemo pd = new PermissionDemo() ;
// pd.show() ;//私有的
//pd.show2();//默认修饰符
//pd.show3() ;//受保护的
pd.show4() ;
}
}
2 面向对象
2.1什么是类? 在Java中如何创建类对象
类:是描述现实世界事物的一组属性和行为的集合!-----> 将事物----定义一个类
类的成员有:成员变量、成员方法、构造方法
成员变量(事物的属性):类中方法外
成员方法(事物中的行为,去掉static):public void show(){ 方法体 }
class Demo{
//成员变量:
//在类中定义,方法外
int num ;
//非静态:去掉static
public void show(){
System.out.pritnln("show Demo") ;
}
}
class Test{
public static void main(String[] args){
//现在访问Demo类的中num变量?
Demo d = new Demo() ; //创建对象
d.num = 100 ; //调用方法
System.out.println(d.num) ;
d.show() ;
}
}
输出结果:100
show Demo
2.2面向对象的思想特点
1)更符合现实生活中的思想行为习惯
2)让复杂的事情简单化
3)角色变化---由执行者变成指挥者(指挥对象做事情)
2.3 面向对象的三大特征
1.封装
封装将类中重要的信息隐藏在内部,不让外部程序直接访问,只能通过该类提供的方法对隐藏信息进行操作和访问。例如我有一部手机,手机里有手机的机型、内存等但一般用户不需要了解详细信息,便将其进行封装,提供设置手机详情让用户进行访问。
实现封装的步骤:
1)将想要隐藏的变量和方法利用private进行修饰
2)在类中提供getXXX(进行调用)和setXXX(进行赋值)
书写格式为:public void setXXX(数据类型 变量名){this.变量名=变量名 }
public 数据类型 getXXX(){ return 变量名}
3)在测试类(main方法所在的类)中先创建对应类的对象,然后进行赋值和调用
例题:
class Demo1{
private String name; //定义私有属性姓名、年龄、性别
private int age;
private String gender;
private void show(){ //创建一个私有方法
System.out.println("Demo1 show");
}
public void show1(){ //利用公共方法show1,对show方法进行调用
System.out.println("Demo1 show1");
show();
}
public Demo1(){} //构造无参
public Demo1(String name, int age, String gender) { //有参构造--跟setXXX
//一样是给成员变量初始化
this.name = name;
this.age = age;
this.gender = gender;
}
public String getName() { //获取名字
return name;
}
public void setName(String name) { //给name赋值
this.name = name;
}
public int getAge() { //获取年龄
return age;
}
public void setAge(int age) { //给age赋值
this.age = age;
}
public String getGender() { //获取性别
return gender;
}
public void setGender(String gender) { //给性别赋值
this.gender = gender;
}
}
public class Demo { //测试类
public static void main(String[] args) {
Demo1 d1 = new Demo1();
d1.setName("小明"); //进行赋值
d1.setAge(15);
d1.setGender("男");
System.out.println(d1.getName()+"---"+d1.getAge()+"---"+d1.getGender());//访问
//d1.show();//报错,方法show是私有方法,不能直接访问
d1.show1();
System.out.println("-----------------------------");
Demo1 d2 = new Demo1("小梁",20,"女"); //通过有参构造也能进行成员变量的初始化
System.out.println(d2.getName()+"---"+d2.getAge()+"---"+d2.getGender());
}
}
输出结果:
![](https://i-blog.csdnimg.cn/blog_migrate/41607902d627d6b0efac1326782ec908.png)
private关键字的特点:
1)被private修饰的成员变量/成员方法(非静态),只能在本类中访问,外界类不能访问!
2)虽然被私有修饰的成员变量以及成员方法(非静态)不能直接访问,但是都可以间接的通 过"public"公共访问访问!
this关键字
Java提供了一个关键字:(局部变量名称隐藏了成员变量名称)this--->代表当前类的对象的地址值引用!
格式:this.成员变量名 = 局部变量名--->将局部变量值赋值给自己类中的成员变量
2.继承
①什么是代码块
什么是Java中的代码块?
Java中的代码块是一个{ }包裹起来的内容!
分类:
1)局部代码块--->方法定义中 作用:限定局部变量的生命周期
2)构造代码块--->类的成员位置定义的{ }
作用:在执行构造方法之前,如果存在构造代码块,先执行构造代码块,
然后在执行构造方法 ,就是给数据进行初始化的!
3)静态代码块--->类的成员位置定义的
static{
方法体
}
特点:跟类相关,类一加载,先执行,而且只执行一次(因为类就加载一次)优先级最大
优先级:
静态代码块 > 构造代码块 > 构造方法!
例题:
class Student{
static{
System.out.println("Student的静态代码块1");
}
public Student(){
System.out.println("Student的无参构造方法");
}
{
System.out.println("student的构造代码块1");
}
public Student(String name){
System.out.println("Student的有参构造方法"+name);
}
static{
System.out.println("Student的静态代码块2");
}
{
System.out.println("student的构造代码块2");
}
}
public class MainTest {
static{
System.out.println("MainTest的静态代码块");
}
public static void main(String[] args) {
Student s = new Student() ;
Student s2 = new Student("高圆圆") ;
}
}
结果:
![](https://i-blog.csdnimg.cn/blog_migrate/1fca84a8147173b9ce95e859c84017d3.png)
结果分析:Student s1= new Student()无参构造想要运行时,但存在静态代码块和构造代码块,所以先走优先级最高的静态代码块,和构造代码块,然后走无参构造;Student s2 = new Student("高圆圆")有参构造想要运行时,因为静态代码块随着类的加载只运行一次,所以先走优先级高的构造代码块,然后走有参构造。
②继承的初步了解
继承的概念:
将多个类的共性内容抽取到一个独立的类中,这个独立的类和这多个类产生一种关系 "继承"
继承的格式:
class 父类名{ }
class 子类名 extends 父类名{ }
继承的好处:
1)可以提高代码的复用性
2)可以增强代码的后期维护
3)类与的类关系:继承关系 是多态的前提条件!
使用"继承"的时机:什么时候使用继承?
class A{
public void show(){}
public void show2(){}
}
class B{
//public void show(){}
public void show3(){}
}
---->优化 class B extends A{}
不能为了使用部分功能就使用继承!
使用继承的前提条件:
如果一个类A是类B一种,或者是类B是类A的一种,才能使用继承,继承的核心思想体现出一种"is a"的关系
举例
水果:苹果、香蕉、菠萝...
人:工人、学生、军人、老师...
实际开发中:
所有的开发原则都必须遵循 "低耦合,高内聚"
耦合:类和类的关系越少越好,耦合性只能降低,不能避免!
内聚:解决某件事情(功能)的执行力!(一个类能够完成的尽量一个类完成,不能产生过多关系!)
继承的特点:
1)在Java语言中,类与类的关系,只支持单继承 (类是Java中最基本的单元)
举例:
class Fu{}
class Fu2{}
class Zi extends Fu,Fu2{} 这种写法错误格式
2)类与类之间虽然不支持多继承,但是可以多层继承!
继承的注意事项:
1)子类继承父类,是可以继承父类所有的东西,只不过父类的私有的属性以及方法只能在本类中访问
子类是不能直接访问到的,但是可以间接的通过公共方法来访问!
2)子类继承父类,不能继承父类的构造方法(无参/有参构造),可以通过 "super"来访问父类的构造 方 法!
例题:
class Fu{
//私有的
private int num = 100 ;
//非私有的
public int num2 = 200 ;
//定义一个成员方法
public void show(){
System.out.println(num) ;
System.out.println(num2) ;
}
//私有方法
private void method(){
System.out.println("method Fu...");
}
//非私有
public void mySelfMethod(){
method(); //调用了私有方法
}
}
//子类
class Zi extends Fu{
//子类的成员方法
public void function(){
System.out.println(num2);
//System.out.println(num); //num是父类私有的成员变量子类不能直接访问
}
}
//测试类
public class Demo {
public static void main(String[] args) {
//创建Zi类对象
Zi z = new Zi() ;
z.function(); //使用自己的成员方法
z.show(); //继承父类的, 虽然num是父类的私有的成员变量,但在Fu类中可以直接使用
//z.method();//父类的私有方法,不能直接访问
System.out.println("------------------------");
z.mySelfMethod();
}
}
结果:
![](https://i-blog.csdnimg.cn/blog_migrate/38437a67d18989798b552aa8a9a99440.png)
③继承关系中的成员问题
1)子类继承父类,子类中 成员变量如果父类中的成员变量名称不一致的情况:比较简单,分别访问即可!
2)子类继承父类,如果子类的成员变量名称和父类的成员变量名称一致,如何访问呢?
a)先在子类的局部位置(子类的成员方法中定义变量:局部变量)找,如果存在,就使用
b)如果子类的局部位置没有,然后才在子类的成员位置找,如果存在,就使用
c)如果子类的成员位置没有,然后在父类的成员位置找,如果存在,就使用
d)如果父类的成员位置也没有,说明当前没有这个变量,就访问报错!
一句话:就近原则!
class Fu{
//父类的成员变量
int num = 20 ;
}
//定义一个子类
class Zi extends Fu{
//子类的成员变量
//int num2 = 30 ;
int num = 100 ;
//子类的成员方法
public void show(){
int num = 30 ; //局部变量
System.out.println(num) ;
System.out.println(this.num);
System.out.println(super.num);
//System.out.println(num2);
}
}
//测试类
public class Demo {
public static void main(String[] args) {
//创建子类对象
Zi z = new Zi() ;
z.show();
}
}
结果:
![](https://i-blog.csdnimg.cn/blog_migrate/60e34f1746d779b5d132f9e714d0279e.png)
结果分析:当局部变量、类中成员变量、父类成员变量的变量名都相同时System.out.println(num) ;会输出离的最近的数值;但this和super能够指定输出,this指向类中成员变量的空间地址值,super指向父类成员变量的空间地址值。故输出100和20.
④如何访问父类构造方法
子类继承父类,子类如何访问父类的构造方法?
通过super关键字
1)子类继承父类,不能继承父类的构造方法,但是可以通过super访问,子类的所有构造方法默认访问父类的无参构造方法!
子类的构造方法的第一句话:都有super() 但隐藏了; 访问父类的无参构造方法
原因:
子类继承父类,可能用到父类的属性(成员变量)这些数据,必须让父类先初始化,然后子类才能初始化(构造方法,就是给数据初始化的) 这种过程----继承中 "分层初始化"
2)永远建议把父类的无参构造方法给出来,可能户导致子类的构造方法报错!
class Fu3{
//假设:姓名,年龄,性别...属性(成员变量)
//父类给一个无参构造方法
public Fu3(){
System.out.println("这是Fu3的无参构造方法");
}
/*public Fu3(String name){
System.out.println("Fu3的有参构造方法,"+name);
}*/
}
//子类
class Zi3 extends Fu3{
//子类的无参构造方法
public Zi3(){
// super() ;//可以隐藏不写
System.out.println("Zi3的无参构造方法");
//super() ; 放在后面,可能初始化多次,jvm编译不让通过! 必须在第一句话
}
//子类的有参构造方法
public Zi3(String name){
//super() ;//可以隐藏不写
System.out.println("Zi3的有参构造方法,"+name);
}
}
//测试类
public class ExtendsDemo5 {
public static void main(String[] args) {
//通过子类的无参构造方法,创建子类对象
Zi3 z = new Zi3() ;
System.out.println("--------------------") ;
//通过子类的有参构造放,创建子类对象
Zi3 zz = new Zi3("hello") ;
}
}
结果:
![](https://i-blog.csdnimg.cn/blog_migrate/fe384759ba12bc0561f6d0b9848cfd8b.png)
结果分析:
Zi3 z = new Zi3() ;子类想创建对象必须先让父类初始化(隐藏修饰符super()),父类的无参构造结束说明父类初始化完毕,走子类的无参构造;
Zi3 zz = new Zi3("hello") ;子类要有参构造创建对象必须让父类初始化(隐藏修饰符super()),父类的无参构造结束说明父类初始化完毕,走子类的有参构造;
总结:子类不管是有参还是无参都会先通过隐藏修饰符super()走父类的无参构造。
⑤继承构造方法注意事项
继承关系中的构造方法的注意事项
子类继承父类,子类的所有构造方法第一句话都隐藏了默认 super() ;但子类构造方法中有this或者super将不再默认super()(访问父类的无参构造);
那么,如果父类中并没有给出无参构造方法,子类会出现什么情况?如何解决?
子类的所有构造方法都会报错!默认都要访问父类无参构造方法(默认机制)
解决方案:
1)自己手动给出父类的无参构造方法(推荐)
2)不给出父类的无参构造方法,怎么解决?
让子类的所有构造方法都直接来访问父类的有参构造方法,只要父类初始化即可!
3)所有的子类的构造方法只要有一个让父类初始化即可!
在子类的无参构造方法中第一句话: this(xxx) ; 访问本类(子类)的有参构造方法
在通过子类的有参构造方法的第一句话:super(xxx) ;访问父类的有构造方法---->父类先初始化完毕完毕
实际开发中:(写继承代码的时候)
子类继承父类,子类的无参构造方法访问父类的无参!
子类的有参构造方法访问父类的有参!
例题1:
class Father{
//手动给出Father的无参
public Father(){
System.out.println("Father的无参构造方法");
}
//Facther的有参构造
public Father(int num){
System.out.println("Father的有参构造方法:"+num) ;
}
}
//定义一个子类
class Son extends Father{
//Son类的无参构造方法
public Son(){
super(100) ; //访问父类的有参构造方法
//this(100) ;//访问本类的有参构造方法
System.out.println("Son的无参构造方法");
}
//Son的有参构造方法
public Son(int num){
//super(20) ; //访问父类的有参构造方法
this() ;//访问本类无参构造方法
System.out.println("Son的有参构造方法:"+num);
}
}
//测试类
public class Demo {
public static void main(String[] args) {
Son s1 = new Son() ;
System.out.println("------------------");
Son s2 = new Son(50) ;
}
}
结果:
![](https://i-blog.csdnimg.cn/blog_migrate/490e8a2ea7593ed1730b5eb8505e7f24.png)
结果分析:
因为子类的有参构造和无参构造中都有this/super所以将不再默认访问父类的无参构造;this()指自己类中的无参构造,super(100)指父类的有参构造。
例题2:
class Person{
public Person(){
System.out.println("这是Person类的无参构造方法");
}
static{
System.out.println("Person的静态代码块");
}
{
System.out.println("Person的构造代码块");
}
}
//子类
class Student extends Person{
public Student(){
//super();
System.out.println("Student的无参构造方法");
}
public Student(String name){
System.out.println("Student的有参构造方法");
}
{
System.out.println("Student的构造代码块");
}
static{
System.out.println("Student的静态代码块");
}
}
public class Demo {
public static void main(String[] args) {
Student s = new Student() ;
Student s2 = new Student("高圆圆") ;
}
}
运行结果:
![](https://i-blog.csdnimg.cn/blog_migrate/574bd0b6b400435c12799109aeb2eeba.png)
结果分析:
Student s = new Student() ;子类通过无参构造创建对象,因为存在父类所以先初始化父类再走子类,父类中存在静态代码块就先走静态代码块,然后走构造代码块,最后进行无参构造,无参构造说明父类初始化完毕,接下来走子类,子类也同理;
Student s2 = new Student("高圆圆") ;因为构造方法没有指定this/super,所以默认super()走父类的无参构造,但构造代码块的优先级更高,所以是先构造代码块然后无参构造然后子类的构造代码块和有参构造方法
⑥static关键字
关于static关键字--->被多个对象"共享,共用"的意思
特点:
1)被static修饰的成员(变量/方法)随着类的加载而加载,优先于对象存在! (对象创建: 类名 对象名 = new 类名() ;)
某个类要先被编译产生-->类名.class--->类在运行的时候,加载过程要将静态的成员都先进入方法区的静态区中!
2)static和this不能共存!
this:代表是当前类对象的地址值引用---说明对象创建完毕,才能使用this.变量名 -->访问成员变量 (对象成员)
static:随着类的加载而加载,被static修饰的成员--->"类成员"
3)如果有一个变量体现出被共享,被共用--->此时用"static"修饰
举例:
水杯中的水 (不行)
饮水机的水(可以被共享)
4)访问方式:(必须记住)
类成员--->被static修饰的,特有访问 方式
类名.变量名; //在访问本类中静态变量
类名.方法名() ;//在访问本类中的静态方法
注意:
我们所说的成员变量/成员方法---->默认 非静态的!
静态static的使用注意事项:
1)非静态的成员方法里面,皆可以访问静态的变量/方法,也可以访问非静态的变量/方法!
2)静态的方法只能访问静态的成员,不能访问静态的
静态只能访问静态!
⑦override:方法重写
继承关系中,成员方法的访问
子类继承父类,如果子类和父类的方法名不一致,分别调用即可! (简单)
如果子类出现了和父类一模一样的方法,如何访问呢?
子类会将父类的功能进行覆盖(复写/重写)--->override:方法重写
例题:
class Fu{
//父类的成员方法
public void show(){
System.out.println("show Fu...");
}
}
//子类
class Zi extends Fu{
//成员方法
public void method(){
System.out.println("method Zi....") ;
}
public void show(){
super.show(); //既沿用了父亲的功能,还有自己的功能!
System.out.println("show zi...");
}
}
//测试类
public class ExtendsDemo {
public static void main(String[] args) {
//创建子类对象
Zi z = new Zi() ;
z.show() ;
z.method() ;
}
}
结果:
![](https://i-blog.csdnimg.cn/blog_migrate/eda2a1136c8e36427f436cf3fb3862c9.png)
⑧final关键字
定义一个父类,子类重写父类的某个成员方法,通过方法重写,最终子类将父类将父类方法覆盖
但是有的时候,父类不让子类将自己的某个成员方法进行重写(为了父类的方法的安全性!),Java提供了关键字--->final
final:是一个状态修饰符 (最终的,无法更改的)
final的特点:
final修饰类时,该类不能继承
final修饰成员方法时,该方法不能被重写
final修饰变量时:
修饰基本数据类型的变量时,变量为常量
修饰引用数据类型的变量时,变量对应的空间地址值无法更改(不能new),但可以重新赋值
常量:
编译时期常量---->基本数据类型:四类八种 (jvm不需要加载)
public static final int a = 10 ;
运行时期常量---->引用数据类型: (jvm进行加载,引用类型 除过String)
int类型--->包装类 类型 Integer类
public static final Integer i = new Integer(10) ;
//i = new Integer(100) ;//报错
开发中自定义常量:
public static final 数据类型 变量名 = 初始化值;
例题:
class Father{
public static final int age = 20 ; //final修饰成员变量,必须给值,此值不能更改!
public final void method(){
System.out.println("method Father..");
}
}
//子类
class Son extends Father{
/*public void method(){//不能重写
System.out.println("method Son");
}*/
public void show(){
final int a = 100 ; //局部变量
//a = 200 ;//数据值不能在更改
System.out.println(a) ;
}
}
//测试类
public class FinalDemo2 {
public static void main(String[] args) {
System.out.println(Father.age); //访问父类中静态常量
}
}
结果:
![](https://i-blog.csdnimg.cn/blog_migrate/2259ffafebdffad856ea137dccee94b1.png)
3.多态
什么是多态?
从宏观角度去说:一个事物(能看到真实存在的)体现出的不同形态!
举例:
水--->固态 气态 液态
从内存角度去说:一个对象它的所在的类型的变化
举例:
Cat c = new Cat() ; //创建一个只猫 从右边--->左边:猫是猫
Animal a = new Cat() ; //堆内存是猫 从右边--->左边:猫是动物
前提条件:
1)必须存在继承关系,才能使用多态
2)必须存在方法重写,子类继承父类,部分功能将父类进行重写,比如:
动物都要吃和睡,具体的动物类:猫/狗/猪,吃和睡的动作不一样
3)必须存在父类引用指向子类对象 ----->多态的 "向上转型"
class 父类名{}
class 子类名 extends 父类名{}
//多态测试---
父类名 对象名 = new 子类名() ;
多态的成员访问特点:
成员变量:编译看左,运行看左!
成员方法(默认都是非静态): 如果子类重写了父类的方法,编译看左,运行看右!
静态方法算不上重写,和静态的都是类成员! (访问方式都是类名来调用的)
构造方法:继承是多态的前提条件,所以在使用父类引用指向子类对象:Fu fu = new Zi() ;
还是要遵循"分层初始化",先让父类构造初始化,然后在是子类构造初始化!
①多态的好处
多态的好处:
1)可以提供代码的复用性(由继承保证的)
2)可以提高代码的扩展性(健壮性)--->由多态保证
父类引用指向子类对象
例题:
class Animal{
public void eat(){
System.out.println("动物需要吃饭");
}
public void sleep(){
System.out.println("动物困了就需要休息");
}
}
//子类
class Cat extends Animal{
@Override
public void eat() {
System.out.println("猫吃鱼");
}
@Override
public void sleep() {
System.out.println("猫趴着睡");
}
}
//狗类
class Dog extends Animal{
@Override
public void eat() {
System.out.println("狗吃骨头");
}
@Override
public void sleep() {
System.out.println("狗侧着睡");
}
}
//子类
class Pig extends Animal{
@Override
public void eat() {
System.out.println("猪吃白菜");
}
@Override
public void sleep() {
System.out.println("猪躺着睡");
}
}
//优化方案2:定义一个动物工具类
class AnimalTool{
//为了让外界不能new,无参构造方法私有化
private AnimalTool(){}
//定义一个方法: 使用猫的功能
/* public static void useCat(Cat c){//形式参数是猫类型
c.eat();
c.sleep();
}
//定义一个方法:使用狗的功能
public static void useDog(Dog d){//形参参数是狗类型
d.eat();
d.sleep();
}
//定义一个方法:使用猪的功能
public static void usePig(Pig p){
p.eat();
p.sleep();
}*/
public static void useAnimal(Animal a){ //形式参数是引用类型--->父类指向子类对象
// 实际参数:Animal animal = new Cat();
a.eat(); //animal.eat() ;
a.sleep(); //animal.sleep() ;
}
}
//测试类
public class Demo {
public static void main(String[] args) {
//使用具体的子类操作
//养了一只狗--创建狗
Dog dog = new Dog() ;
dog.eat();
dog.sleep();
System.out.println("-------------------------------------------------");
//优化:在测试类中提供两个静态方法,方法形式参数传递狗或者猫
//有一只猫对象
Cat cat = new Cat() ; //有名字的对象
useCat(cat) ;
useDog(new Dog());
System.out.println("----------------------优化方案2------------------------------");
//上面代码不好: 随着具体的类越来越多,useXXX(具体的动物类型)方法就会很多,代码量很多!
//定义一个动物工具类 AnimalTool
//AnimalTool at = new AnimalTool();
/* AnimalTool.useCat(new Cat());
AnimalTool.useDog(new Dog());
Pig pig = new Pig() ;
AnimalTool.usePig(pig);*/
//上面代码继续优化:随着具体类型增加,AnimalTool中的静态功能,越来越多
//多态的特点:父类引用指向子类对象:可以提高代码的扩展性
Animal animal = new Cat() ; //堆内存指向的是猫 (猫是的动物)
AnimalTool.useAnimal(animal);
animal = new Dog(); //堆内存是狗 (狗是动物)
AnimalTool.useAnimal(animal);
}
//定义一个方法: 使用猫的功能
public static void useCat(Cat c){//形式参数是猫类型
c.eat();
c.sleep();
}
//定义一个方法:使用狗的功能
public static void useDog(Dog d){//形参参数是狗类型
d.eat();
d.sleep();
}
}
结果:
![](https://i-blog.csdnimg.cn/blog_migrate/26cea93c9d553ad7cb947d801c645631.png)
②多态的弊端
多态的弊端:
不能访问子类的特有功能 父类名 对象名 = new 子类名() ; "向上转型"
如何解决呢?
方案1:
直接创建具体的子类对象 子类名 对象名 = new 子类名() ;
虽然可以这种方式可以,但是从内存角度考虑:消耗资源,浪费空间,又需要去开辟堆内存!
方案2:
多态本身:父类引用指向子类对象,能不能将父类的引用转换成子类型?
"向下转型"---->强转类型转换的格式 ,前提必须有"向上转型"
数据类型 变量名 = (目标数据类型)(初始化值或者表达式) ;
例题:
class Fu{
public void show(){
System.out.println("show Fu");
}
}
//子类
class Zi extends Fu{
public void show(){
System.out.println("show Zi");
}
//特有功能
public void playGame(String gameName){
System.out.println("会玩"+gameName+"游戏");
}
}
//测试类
public class Demo {
public static void main(String[] args) {
//父类引用指向子类对象
Fu fu = new Zi() ;
fu.show() ;
//fu.playGame("csgo") ;无法使用playGame方法()父类没有
System.out.println("-----------------------------") ;
//访问子类特有功能
Zi z = new Zi() ;
z.playGame("战地5");
System.out.println("------------------------------");
/**
* "向下转型"---->强转类型转换的格式 ,前提必须有"向上转型"
* * 数据类型 变量名 = (目标数据类型)(初始化值或者表达式) ;
*/
Zi z2 = (Zi)fu;
z2.playGame("csgo");
}
}
结果:
![](https://i-blog.csdnimg.cn/blog_migrate/734492b1b621b627fc93f059e170161d.png)
4 抽象
①什么是抽象?
举例:
将猫和狗的共性内容,抽取到了动物(本身就是统称,概括性的)了中,比如:吃和睡的功能,但是在动物了中
将吃和睡给出了具体体现,只有看到具体的事物才能知道它具体吃和睡的行为!所以在父类将这些行为,只是给出一个方法声明即可!
仅仅给出方法的声明---->含义没有方法体{}
有抽象的方法的必须为抽象类
抽象类中不一定都是抽象方法!(部分的功能,抽象功能,必须让子类必须重写!)
抽象方法(成员方法)的格式:
权限修饰符 abstract 返回值类型 方法名(空参/带参) ;
抽象类的本质:
强制子类必须将父类的所有的抽象方法,必须实现(重写)
抽象类的特点:
1)不能实例化(不能new 创建对象)
2)抽象类的子类一定有具体类,否则无法进行实例化的!
抽象类的成员特点:
1)成员变量:
可以是变量也可以自定义的常量
2)成员方法
既可以有抽象方法,也可以有非抽象方法!
3)构造方法
还存在继承关系,分层初始化--->先父类构造初始化,然后是子类构造初始化!
无参构造方法/有参构造方法都可以存在,目的都是为了数据进行初始化!
抽象abstract关键字不能和哪些关键字共存?
abstract不能和private共用:
被private修饰的只能在当前类访问,而abstract修饰的方法,它需要强制子类进行重写;
abstract不能和static共用:
abstract修饰的成员方法,需要被子类重写,还是抽象类多态进行实例化Fu fu = new Zi() ;
而static随着类的加载而加载(静态方法算不上重写),跟类相关的!
abstract不能和final共用:
被final修饰的成员方法不能被重写,而abstract修饰的成员方法,强转子类重写!
abstract:用在类上,标记这个类----抽象类
用在方法上,标记这个方法是一个抽象方法!
结合public使用居多
5.接口
什么是接口?
举例:
猫或者狗本身这个事物不具备"跳高"的功能,经过后天 驯养员的培养,猫和狗就具备了"跳高的功能"
接口体现的是这个事物本身不具备的功能,是一种额外的扩展功能!只要这个事物实现了接口,它就具备这个功能!
如何定义接口
java定义接口: interface 接口名{}
接口的子类(子实现类) implements 接口名{
强制子实现类必须将接口中所有抽象方法必须重写!(实现)
}
接口的特点:
1)接口不能实例化(不能创建对象)
2)接口如何实例化?
接口多态
接口名 对象名 = new 接口的子实现类名() ; (前提:子实现类是非抽象的,就是一个具体类)
开发中:
接口名和子实现类的命名规范(开发项目中)
举例:
接口名: interface Inter{}
接口的子实现类命名: 接口名 +Impl
class InterImpl implements Inter{}
接口中的成员特点:
成员变量:只能是常量 存在默认修饰符 public static final
成员方法:(非静态):只能是抽象方法,存在默认修饰符 public abstract
在接口中是可以定义静态方法,必须有方法体(特例)
构造方法: 没有构造方法! 因为子实现类和接口的关系是implements实现关系,
只是将接口暴露的额外功能进行实现!
例题:
//定义一个接口
interface Inter{
/*public Inter(){
}*/
// public int num = 10 ;
public static final int num = 10 ;
//public static int num2 = 20 ;
public static final int num2 = 20 ;
/*void show(){//接口只能抽象方法
}*/
public abstract void show() ;
void show3() ;
//静态方法
public static void show2(){
System.out.println("show2()...");
}
}
//接口的子实现类 InterImpl实现Inter接口
class InterImpl implements Inter{
int num = 100 ;
@Override
public void show() {
System.out.println("show InterImpl");
}
@Override
public void show3() {
System.out.println("show3 InterImpl");
}
}
//测试类
public class InterfaceDemo2 {
public static void main(String[] args) {
//接口多态的测试
Inter inter = new InterImpl() ;
System.out.println(inter.num) ;//多态的成员变量的访问
System.out.println(Inter.num);
// inter.num = 200 ;
System.out.println(Inter.num2) ;
//inter.num2 = 300 ; final修饰的变量是一个常量,不能在赋值
Inter.show2();
}
}
结果:
![](https://i-blog.csdnimg.cn/blog_migrate/5c3f27239cc719bb2829f1c2e1af3789.png)
方法的形式参数问题: 只研究引用类型
方法形式参数:
具体类:调用该方法,此时实际参数需要的是当当前类的对象!
抽象类:调用该方法,此时实际参数需要的是当前抽象类的子类对象!
接口类型:调用该方法,此时实际参数需要的是接口的子实现类对象!
开发中:方法形式参数是具体类以及接口情况居多的!
//定义一个接口
interface Love{
public abstract void love() ;
}
//定义一个类:LoveDemo
class LoveDemo{
public void method(Love love) {//方法的形式参数是一个接口? 接口不能new,需要接口的子实现类对象
love.love();
}
}
//需要有定义接口的子实现类,实现Love接口
class LoveImpl implements Love{
@Override
public void love() {
System.out.println("love Java!");
}
}
//测试类
public class ArgsDemo3 {
public static void main(String[] args) {
//要访问LoveDemo类中的method方法?
LoveDemo ld = new LoveDemo() ;
// Love l = new Love() ;//接口不能实例化
// ld.method(l);
//接口多态:接口名指向子实现类
Love l = new LoveImpl() ;
ld.method(l);
System.out.println("--------------------------");
new LoveDemo().method(new LoveImpl()) ;
}
}
结果:
![](https://i-blog.csdnimg.cn/blog_migrate/93b0fe9c9a6262506bd35e4cba335112.png)
方法的返回值引用类型:
方法的返回值如果是引用类型:
具体类:需要返回该具体类的对象!
抽象类:需要返回该抽象类的子类对象!
接口:需要返回接口子实现类对象!
例题:
//定义一个接口
interface Mary{ //结婚的接口
public abstract void mary1() ;
}
//定义一个MaryDemo
class MaryDemo{
public Mary method(){
//?
//return new Mary() ;//接口不能new
//方式1:
//Mary mary = new MaryImpl() ;
// return mary ;
//方式2:
return new MaryImpl() ;
}
}
//需要定义接口的子实现类
class MaryImpl implements Mary{
@Override
public void mary1() {
System.out.println("要结婚了,很开心...");
}
}
//测试类
public class Demo {
public static void main(String[] args) {
//需求:访问MaryDemo类中的method方法?
MaryDemo md = new MaryDemo() ;
Mary mary = md.method();
mary.mary1();
System.out.println("--------------------------");
Mary mary2 = new MaryDemo().method();
mary2.mary1();
}
}
结果:
![](https://i-blog.csdnimg.cn/blog_migrate/2938764a19a82fdba66cd4f80d529dd2.png)
6.包的含义(了解)
package:在真实开发中,代码需要分层,借助包名
公司域名反写.pojo:存储的实体类举例:商品类/用户类/订单类/购物车/医生 等等
Order订单类
.service:存储业务接口层OrderService
.service.impl:业务接口实现层 OrderServiceImpl:订单业务接口实现
.dao:存储数据访问接口(Data Access Object:数据访问 对象) OrderDao
.dao.impl: 数据访问接口实现---->访问数据库:获取数据库
.utils :存储的工具代码(自定义的工具,jdk提供/第三方提供的)
.test :测试代码-----单元测试 junit.jar包
面试题
局部变量和成员变量的区别?
类中的书写位置不同
成员变量:在类中,方法外
局部变量:在方法定义中或者方法声明上
jvm内存位置不同
成员变量:在堆内存中
局部变量:在栈内存中
生命周期不同:
成员变量:随着对象的创建而存在,随着对象的创建完毕并且使用完
等待垃圾回收器回收(不会立即回收)而消失!
局部变量:随着方法调用而存在,随着方法调用结束而消失
初始化值不同:
成员变量:存在系统默认初始化,也可以显示初始化
局部变量:总之:在使用局部变量之前,必须赋值,不赋值不行!