1.局部变量和成员变量的区别?
1)类中的书写位置不同
局部变量:在方法定义中或者方法声明上
成员变量:在类中,方法外~
2)内存位置不同
局部变量:在栈内存中
成员变量:在堆内存中
3)生命周期不同
局部变量:随着方法调用而存在,随着方法调用结束而消失
成员变量:随着对象的创建而存在,随着对象创建完毕,并且使用完毕,等待垃圾回收器回收而消失
4)初始化不同
局部变量:必须在使用之前,必须初始化,否则 提示"可能尚未初始化变量"
成员变量:可以不初始化,系统默认进行初始化,也可以显示初始化
2.this关键字的含义
this:代表当前类对象的地址值引用!
出现的原因:
属性私有化,外界类不能直接去访问成员变量,通过公共的成员方法setXXX(xx),进行赋值访问,存在成员变量和局部变量名称一致的情况,为了区分成员变量和局部变量 ;
this.成员变量名 = 局部变量名;
3.什么是构造方法?构造方法的目的是什么
什么是构造方法:
构造方法:
1)方法名和类名相同
2)没有返回值类型
3)连void没有
构造方法是可以重载的!
构造方法目的:
就是初始化成员变量;
class Student{
private String name;
private int age ;
public Student(){}
public Student(String name,int age){
this.name = name ;
this.age = age ;
}
}
4.给成员变量赋值的方式有几种
setXXX方法赋值
构造方法赋值:有参构造方法
5.Student s = new Student() ;做了哪些事情?(内存中)
1)加载学生类,----Student.class
2)在栈内存为s变量开辟栈内存空间
3)new Student()---->在堆内存中申请空间
4)通过无参构造方法为成员变量进行默认初始化
5)申请的堆内存空间里面的成员变量默认初始化完毕,产生堆内存 “空间地址值”
6)将堆内存中"空间地址值" 赋值给栈内存的变量s
7)栈内存的变量s指向堆内存空间地址值!
6.一个标准类的写法格式(重点)
class Student{
//成员变量私有化
private String name ;
private int age;
//无参构造方法
public Student(){}
//有参构造方法
public Student(String name,int age){
this.name = name ;
this.age =age;
}
//公共的成员访问方法
public void setName(String name){
this.name = name ;
}
public String getName(){
return name ;
}
public void setAge(int age){
this.age =age;
}
public int getAge(){
return age ;
}
}
形式参数是引用类型(重点)
package 形参是引用数据类型;
class Dog{
public void eat(String toeat){//有参函数
System.out.println("狗子正在吃"+toeat);
}
}
class DogDemo {
public void Run(Dog dog){//方法的形式参数是一个引用类型:Dog类 ,实际调用,需要去创建Dog类的对象!i//
dog.eat("牛排");
/*引用的是eat方法;由于引用的方法有参所以这里也得有参*/
}
}
public class ArgsDemo2 {
public static void main(String[] args) {
Dog d=new Dog();
DogDemo dd=new DogDemo();
Dog i=new Dog();//分别创建对象
d.eat("骨头");//引用eat方法
dd.Run(i);//引用的是Run方法
}
}
匿名对象
·
格式:
- 没有名字的对象:格式
- new 类名() ;
- 匿名对象的特点:
- 1)直接在堆内存中开辟空间,使用完毕,被垃圾回收器回收(用完就回收了)
- 2)匿名对象在实际开发中使用居多; 匿名对象不要使用多次,使用一次即可!
- 3)匿名对象可以作为参数传递
- 有名字的对象:格式
- 类名 对象名 = new 类名() ;
·
·
package 匿名对象;
class Car{//车类
public void drive(String className){
System.out.println("汽车正在"+className);
}
}
class CarDemo{
public void method(Car c) {
c.drive("冲向悬崖");
}
}
public class NoName {
public static void main(String[] args) {
//普通版本==
// StudentDemo sd=new StudentDemo();
Car c=new Car();
// sd.method(c);
// System.out.println("----------");
// sd.method(new Car());
// System.out.println("----------");
//匿名对象版本==格式:匿名对象就是=>new 类名();
new CarDemo().method(c);//没有前面的
/*其实就是前面的sd.method(c)这个访问方法写成
* new CartDemo().method(c); 其中的sd==new CarDemo
* 创建对象的时候去掉前面的CarDemo sd= */
}
}
:注释掉的地方是其他办法 这里只保留了匿名方法
# **static**
每一个对象都需要在堆内存中开辟空间,在堆中需要进行默认初始化和显示初始化,同一个"属性"都需进行初始化操作,比较麻烦!
### **Java提供了一个关键字 "static"---本身的概念 "共享,共用的意思"**
package StaticDemo;
class Person{
//static 愿意共享的意思 定义一个person类
private String name;
private int age;
private static String country;
//加了static 就是说可以共享这个定义的量
public Person(String name,int age){
this .name=name;
this.age=age;
//不用写country 因为被static共享了
}
public Person(String name,int age,String country){
this.name = name ;
this.age = age ;
this.country = country ;
}//再写一个带country是因为至少得有一个带 用来接收下面的第一个带国家的实参
public void show(){
System.out.println("姓名"+name+"年龄"+age+"国家"+country);
}
}
class Test {
public static void main(String[] args) {
Person p=new Person("杰克",25,"USA");
p.show();
Person p2=new Person("麦克",21);
p2.show();
Person p3=new Person("鲁斯",18);
p3.show();
Person p4=new Person("张三",23);
p4.show();
}
}
静态static 特点(重点)
Ctrl+N全局搜索
·
1)被static修饰的成员(变量/方法)随着类的加载而加载,优先于对象存在! (对象创建: 类名 对象名 = new 类名() 😉
·
- 某个类要先被编译产生–>类名.class—>类在运行的时候,加载过程要将静态的成员都先进入方法区的静态区中!
- 2)static和this不能共存!
- this:代表是当前类对象的地址值引用—说明对象创建完毕,才能使用this.变量名 -->访问成员变量 (对象成员)
- static:随着类的加载而加载,被static修饰的成员—>“类成员”
- 3)如果有一个变量体现出被共享,被共用—>此时用"static"修饰
*
- 举例:
- 水杯中的水 (不行)
- 饮水机的水(可以被共享)
- 4)访问方式:(必须记住)
- 类成员—>被static修饰的,特有访问 方式
- 类名.变量名; //在访问本类中静态变量
=>Demo.num2
- 类名.方法名() ;//在访问本类中的静态方法=>Demo.method
*
```
·
注意事项
- 我们所说的成员变量/成员方法---->默认都是 非静态的!
1)非静态的成员方法里面,皆可以访问静态的变量/方法,也可以访问非静态的变量/方法!
2)静态的方法只能访问静态的成员,不能访问非静态的
-记住: 静态只能访问静态!
代码块(重点)
概念
Java中的代码块是一个{}包裹起来的内容!
分类
·
局部代码块—>方法定义中 作用:限定局部变量的生命周期
- 构造代码块—>类的成员位置定义的{}
- 作用:在执行构造方法之前,如果存在构造代码块,先执行构造代码块,
- 然后在执行构造方法 ,就是给数据进行初始化的!
- 静态代码块—>类的成员位置定义的
。。。。。。。。。。。。。。。。。。。。。。。
- static{
- }
- 特点:跟类相关,类一加载,先执行,而且只执行一次(因为类就加载一次)
- 优先级最大
·
优先级
·
静态代码块 > 构造代码块 > 构造方法!
·
\## 普通代码块顺序例子
\```java
class Student2{
static{
System.out.println("Student的静态代码块1") ;
}
public Student2(){
System.out.println("Student的无参构造方法") ;
}
{
System.out.println("Student的构造代码块1") ;
}
{
System.out.println("Student的构造代码块2") ;
}
public Student2(String str){
System.out.println("Student的有参构造方法") ;
}
static{
System.out.println("Student的静态代码块2") ;
}
}
class StudentTest{
static{
System.out.println("高圆圆已经42了,我很伤心") ;
}
public static void main(String[] args){
Student2 s = new Student2() ;
Student2 s2 = new Student2("hello") ;
}
}
走法:先走所有的static代码块=>
“ static{System.out.println("高圆圆已经42了,我很伤心");}”
“static{System.out.println("Student的静态代码块1");}”
“ static{System.out.println("Student的静态代码块2");}”
再走有/无参构造代码块=>
“{System.out.println("Student的构造代码块1");}”
“ {System.out.println("Student的构造代码块2") ;}”
再走有/无参构造方法的普通代码块=>
“{System.out.println("Student的无参构造方法");}”
“{System.out.println("Student的构造代码块1");}”
“{System.out.println("Student的构造代码块2");}”
此时 Student2 s = new Student2() ;已经运行结束了 接下来执行 Student2 s2 = new Student2("hello") ;这个类对象也就是上面的有参构造函数
//解释一下 这里为啥要再走一遍构造代码块1和2,因为static走一遍就消失了,但是构造代码块又不消失,static
//消失,走方法,无参的构造方法执行了一遍了,不再执行了,构造代码块和构造代码块2就会再次运行然后走下面的
//有参构造方法
最后走有参构造方法=>
“{System.out.println("Student的有参构造方法");}”运行结束
子类父类叠加代码块顺序例子!
/**
* 看程序,写结果
* 考点:
* 代码块的优先级
* 静态代码块 > 构造代码块 > 构造方法
* 继承关系问题
* 子类的所有构造方法默认父类的无参构造方法,目的就是让父类初始化的,然后在子类初始化!
*/
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的有参构造方法"+name);
}
{
System.out.println("Student的构造代码块");
}
static{
System.out.println("Student的静态代码块");
}
}
public class ExtendsTest2 {
public static void main(String[] args) {
Student s = new Student() ;
Student s2 = new Student("高圆圆") ;
}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nmv3cAkd-1678542654470)(file:///C:\Users\29903\AppData\Local\Temp\ksohtml16652\wps1.jpg)]
子类父类叠加代码块顺序例子!
class Root {
static {
System.out.println("Root的静态初始化块");
}
{
System.out.println("Root的普通初始化块");
}
public Root() {
System.out.println("Root的无参数的构造器");
}
}
class Mid extends Root {
static {
System.out.println("Mid的静态初始化块");
}
{
System.out.println("Mid的普通初始化块");
}
public Mid() {
System.out.println("Mid的无参数的构造器");
}
public Mid(String msg) {
this();
System.out.println("Mid的带参数构造器,其参数值:" + msg);
}
}
class Leaf extends Mid {
static {
System.out.println("Leaf的静态初始化块");
}
{
System.out.println("Leaf的普通初始化块");
}
public Leaf() {
System.out.println("Leaf的构造器");
}
}
class LeafTest {
public static void main(String[] args) {
new Leaf();
}
}
结果:
Root的静态初始化块
Mid的静态初始化块
Leaf的静态初始化块
Root的普通初始化块
Root的无参数的构造器
Mid的普通初始化块
Mid的无参数的构造器
Leaf的普通初始化块
Leaf的构造器
继承
Object是所有的子类的父类 最高权限
定义:将多个类的共性内容抽取到一个独立的类种,让这个类和多个类产生一种关系:继承
目的好处:
1 提高代码的复用性
2 增强代码后期维护
3 类与类的关系 继承关系 是多态的前提条件!
4 不能为了部分功能就用继承
5 使用的前提是:如果一个类A是类B的一种,或者类B是类A的一种!
核心思想体现一种“is a”的关系
特点
类是java中最基本的单元
1.JAVA语言中,类与类的关系 只支持单继承,不支持多继承
反例:
class Fu{}
classFu2{}
class Zilei extends Fu,FU2{}
2.类和类之间虽然不支持多继承 但是支持多层继承
例子:
class GrandFather{
publiv void methond1)(){
System.out.println(“我是爷爷”);}
}
clas Father extends GrandFather{
publiv void methond1)(){
System.out.println(“我是爸爸”);}
}
class son extends Father{
publiv void methond1)(){
System.out.println(“我是儿子”);}
}
…
注意事项
继承的注意事项:
1)子类继承父类,是可以继承父类所有的东西,只不过父类的私有的属性以及方法只能在本类中访问;子类是不能直接访问到的,但是可以间接的通过公共方法来访问!
2)子类继承父类,不能继承父类的构造方法(无参/有参构造),可以通过 "super"来访问父类的构造方法!
普通继承的例子
写错位置了…
package ExtendsDemo;
class person{
public void Eat(){
System.out.println("人饿了要吃饭");
}
public void Sleep(){
System.out.println("人困了要睡觉");
}
}
class Man extends person{}
class Woman extends person{}
public class Demo1 {
public static void main(String[] args) {
Man m = new Man();
Woman w = new Woman();
m.Sleep();
m.Eat();
w.Eat();
w.Sleep();
}
}
实际开发原则必须遵守“低耦合,高内聚”
耦合: 类和类的关系越少越好 耦合性只能降低 不能避免
内聚: 解决某件事情或者功能的执行力 一个类能完成尽量一个类完成
子类继承父类,子类如何访问父类的构造方法?
通过super关键字
*** 1)子类继承父类,不能继承父类的构造方法,但是可以通过super访问,子类的所有构造方法默认访问父类的无参构造方法!
** 子类的构造方法的第一句话:都有super() ; 访问父类的无参构造方法*
*** 原因:
** 子类继承父类,可能用到父类的属性(成员变量)这些数据,必须让父类先初始化,然后子类才能初始化(构造方法,就是给数据初始化的)*
*** 这种过程----继承中 “分层初始化”
** 2)永远建议把父类的无参构造方法给出来,可能导致子类的构造方法报错*
静态代码块 > 构造代码块 > 构造方法
** 继承关系问题*
*** 子类的所有构造方法默认父类的无参构造方法,目的就是让父类初始化的,然后在子类初始化!
子类继承父类,如果子类的成员变量名称和父类的成员变量名称一致,如何访问呢?
一个类的成员:
成员变量
成员方法
构造方法
子类继承父类,子类中 成员变量如果父类中的成员变量名称不一致的情况:比较简单,分别访问即可!
子类继承父类,如果子类的成员变量名称和父类的成员变量名称一致,如何访问呢?
a)先在子类的局部位置(子类的成员方法中定义变量:局部变量)找,如果存在,就使用
b)如果子类的局部位置没有,然后才在子类的成员位置找,如果存在,就使用
c)如果子类的成员位置没有,然后在父类的成员位置找,如果存在,就使用
d)如果父类的成员位置也没有,说明当前没有这个变量,就访问报错!
一句话:就近原则!
this和super在当子类变量名和父类一样时的用法
System.out.println(num);//访问局部变量
System.out.println(this.num);//访问当前类的成员变量
System.out.println(super.num);//访问父类的成员变量
需要在控制台分别打印30,20,10
class Test{
public static void main(String[] args){
Zi zi = new Zi();
zi.show() ;
}
}
class Fu{
int num = 10;
}
class Zi extends Fu{
int num = 20 ;
public void show(){
int num = 30 ;
System.out.println(num);//访问局部变量
System.out.println(this.num);//访问当前类的成员变量
System.out.println(super.num);//访问父类的成员变量
}
}
方法重写
/*
*** 继承关系中,成员方法的访问*
***** 子类继承父类,如果子类和父类的方法名不一致,分别调用即可! (简单)
***** 如果子类出现了和父类一模一样的方法,如何访问呢?
*** 子类会将父类的功能进行覆盖(复写/重写)—>override:方法重写**
多态
什么是多态?
从宏观角度去说:一个事物(能看到真实存在的)体现出的不同形态!
举例:
水—>固态 气态 液态
从内存角度去说:一个对象它的所在的类型的变化
举例:
Cat c = new Cat() ;
Animal a = new Cat() ; //堆内存是猫 从右边—>左边:猫是动物
*** 前提条件:
** 1)必须存在继承关系,才能使用多态*
*** 2)必须存在方法重写,子类继承父类,部分功能将父类进行重写,比如:动物都要吃和睡,具体的动物类:猫/狗/猪,吃和睡的动作不一样
** 3)必须存在父类引用指向子类对象 ----->多态的 “向上转型”*
*** class 父类名{}
** class 子类名 extends 父类名{}*
*** //多态测试—
** 父类名 对象名 = new 子类名() ;*
*** 父类名 对象名 = new 子类名() ;
** 多态的成员访问特点:*
*** 成员变量:编译看左,运行看左!
*** 成员方法(默认都是非静态): 如果子类重写了父类的方法,编译看左,运行看右!
** 静态方法算不上重写,和静态的都是类成员! (访问方式都是类名来调用的)*
** 构造方法:继承是多态的前提条件,所以在使用父类引用指向子类对象:Fu fu = new Zi() ;*
*** 还是要遵循"分层初始化",先让父类构造初始化,然后在是子类构造初始化!
***/
多态的好处
* 多态的好处:
-
1)可以提供代码的复用性(由继承保证的)
-
2)可以提高代码的扩展性(健壮性)--->由多态保证
-
父类引用指向子类对象
多态弊端
多态的弊端:
** 不能访问子类的特有功能 父类名 对象名 = new 子类名() ; “向上转型”*
** 如何解决呢?*
*** 方案1:
** 直接创建具体的子类对象 子类名 对象名 = new 子类名() ;*
*** 虽然可以这种方式可以,但是从内存角度考虑:消耗资源,浪费空间,又需要去开辟堆内存!
** 方案2:*
*** 多态本身:父类引用指向子类对象,能不能将父类的引用转换成子类型?
** “向下转型”---->强转类型转换的格式 ,前提必须有"向上转型"*
*** 数据类型 变量名 = (目标数据类型)(初始化值或者表达式) ;
package Test;
//父类
public class Work {
private String name;
private String emid;
private int salary;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getEmid() {
return emid;
}
public void setEmid(String emid) {
this.emid = emid;
}
public int getSalary() {
return salary;
}
public void setSalary(int salary) {
this.salary = salary;
}
public Work(){}
public Work(String name, String emid, int salary) {
this.name = name;
this.emid = emid;
this.salary = salary;
}
public void work(){
System.out.println("人都需要工作");
}
}
package Test;
//子类1
public class programer extends Work {
public programer(String name, String emid, int salary) {
super(name, emid, salary);
}
public programer() {
}
//重写父类方法 初始化父类
public void work(){
System.out.println("程序员每天敲代码");
}
//子类特有的功能
public void study(){
System.out.println("程序员爱喝咖啡");//特有功能
}
}
package Test;
//子类2
public class Mannger extends Work{
private int bouns;
public int getBouns() {
return bouns;
}
public Mannger(){}
public Mannger(String name, String emid, int salary, int bouns) {
super(name, emid, salary);
this.bouns = bouns;
}
public void setBouns(int bouns) {
this.bouns = bouns;
} public Mannger(int bouns) {
this.bouns = bouns;
}
public void work(){//重写父类方法 初始化父类
System.out.println("经理平时就香车美女谈生意");
}
public void tread(){
System.out.println("经理全国各地跑业务");//特有功能
}
}
package Test;
//测试类
public class WorkMan {
public static void main(String[] args) {
Work w = new programer();
w.setEmid("333");
w.setName("王二小");
w.setSalary(15000);
System.out.println("注意看这个男人叫" + w.getName() + "工号" + w.getEmid() + "薪水" + w.getSalary());
programer pro = (programer) w;//强转的时候先写 programer pro=w;再分号后面ait +回车
pro.study();
Work w2 = new Mannger();
w2.setName("李成功");
w2.setEmid("x001");
w2.setSalary(20000);
System.out.println("注意看这个男人叫" + w2.getName() + "工号" + w2.getEmid() + "薪水" + w2.getSalary() + "奖金是" + ((Mannger) w2).getBouns());
Mannger man = (Mannger) w2;
((Mannger) w2).tread();
((Mannger) w2).setBouns(2000);
}
}
1.静态代码块,构造代码块,构造方法的优先级
优先级
静态代码块 > 构造代码块 > 构造方法
2.static关键字的特点
1.被static修饰的变量/方法,随着类的加载而加载,优先于对象存在
2.staitc关键字不能和this共存
3.具有"共享,共用"的意思
4.特有访问方法,使用类名访问 (类成员)
类名.变量名;
类名.方法名();
3.什么是继承?继承的好处
继承:
将多个类的共性内容抽取到一个独立的类中,让这个独立的类和这多个类产生一种关系,“extends”
好处:
1)可以提高代码的复用性
2)可以增强代码的维护性
3)类与类的关系,是多态前提条件!
所有开发原则必须遵循"低耦合,高内聚"
4.继承的特点
特点:
1)类与类之间,在Java语言中,只支持单继承,不支持多继承
2)不支持多继承.可以多层继承
5.继承中,子类和父类出现的成员变量名称一致的情况,如何访问
继承关系中,成员变量一致:
1)在子类的局部位置先找,如果有就使用;
2)如果子类局部位置没有,会在子类的成员位置中找,有就使用;
3)如果子类的成员位置也没有,会在父类的成员位置找,有就使用
4)如果父类中的成员位置也没有,访问了不存在的变量(编译报错)
class Fu{}
class Zi extends Fu{}
//测试
Zi z = new Zi() ;
6.继承中,子类继承父类,构造方法如何访问?
子类继承父类,构造方法的访问:
构造方法是不能继承的!
构造方法目的为了给类的成员进行初始化;
继承关系中,子类继承父类,默认所有的子类的构造方法通过super() ;访问父类的构造方法
建议:描述一个事物,使用"类"来进行定义,永远 给无参构造方法;
如果没有给出父类的构造方法,但是给了父类的有参构造方法,那么默认子类的所有构造方法都会报错!
解决方案:
1)要么直接手动给出父类无参
2)假设不给给出父类无参构造方法,直接让子类的所有构造方法通过super(xxx);来访问父类的有参
3)子类所有的构造方法中只要有一个能够父类初始化!
class Fu{
//公共的属性
public Fu(){}
}
class Zi extends Fu{
public Zi(xx xx){
//子类的有参构造方法
}
}
final
·
定义一个父类,子类重写父类的某个成员方法,通过方法重写,最终子类将父类将父类方法覆盖
- 但是有的时候,父类不让子类将自己的某个成员方法进行重写(为了父类的方法的安全性!),Java提供了关键字—>final
- final:是一个状态修饰符 (最终的,无法更改的)
·
·
面试题
方法重写和方法重载的区别
override和overload的区别
方法重载:
在定义方法的时候,为了提高功能的扩展性,同一个方法名,可以使用不同的参数进行传递!
方法名相同,参数列表不同,与返回值无关!
参数列表不同:
1)参数个数
2)参数类型
3)类型的先后顺序
方法重写:
是在继承关系中使用的;
子类继承父类,子类的功能想沿用父类的功能,同时使用自己的功能,子类出现了和父类一模一样的方法,–方法重写(覆盖/复写)
子类继承父类,如果要重写父类的功能,访问权限不能够更低,最起码跟父类的成员方法一致,要么永远public!
举例:
人:
eat() 吃的功能
员工:
work() 都需要工作
程序员也是员工 ---->日日夜夜敲带
项目奖经理也是员工---->吃饭喝酒谈项目
this和super的区别
概念区别
this:代表是当前类对象的地址值引用
super:代表父类的对象的地址值引用(父类的空间标识)
成员访问的区别:
this.变量名; 访问本类的成员变量
super.变量名; 访问父类的成员变量
this.方法名() ; 访问本类成员方法
super.方法名() ;访问的父类的成员方法
this() ; 访问本类的无参构造方法
this(xxx); 访问的本类的有参构造方法
super() ;访问的是父类的无参构造方法
super(xxx) ; 访问的是父类的有参构造方法
final修饰基本数据类型和修饰引用数据类型 的区别?
final修饰的引用数据类型,当前不能在开辟堆内存(不能重新new),里面的成员变量依然可以进行赋值
final修饰的基本数据类型,基本数据数据值不能在改变!
final的特点,finalize,finally的区别?
final是一个状态修饰符.最终的,无法更改的!
修饰类,该类不能被继承
修饰成员方法,该方法不能被重写
修饰变量,此时变量是一个常量;不能在重写赋值
finalize:是一个方法名,是后面jvm当前确定堆内存中对象没有更多引用的时候,来通过垃圾器来调用进行回
收的方法!
finally:是关键字,是后面Java中去处理"异常"的一种格式:捕获异常
标准格式
try{
//可能出现问题代码
}catch(异常类名 变量名){
处理异常
}finally{
//释放相关的系统资源 (后面学习IO流,读取文件/写文件等等)
}
*** 什么时候将一个变量定义为成员变量?**
变量—>成员变量/局部变量
将一个变量定义为成员变量的时机:
** 如果这个变量能够描述现实世界事物的属性—>定义为成员变量,否则都是"局部变量*
抽象abstract
什么是抽象?
- 举例:
-
将猫和狗的共性内容,抽取到了动物(本身就是统称,概括性的)了中,比如:吃和睡的功能,但是在动物了中
- 将吃和睡给出了具体体现,只有看到具体的事物才能知道它具体吃和睡的行为!所以在父类将这些行为,只是给出一个方法声明即可!
- 仅仅给出方法的声明---->含义没有方法体{},抽象功能---->
-
有抽象的方法的必须为抽象类
-
抽象类中不一定都是抽象方法!(部分的功能,抽象功能,必须让子类必须重写!)
- 抽象方法(成员方法)的格式:
-
权限修饰符 abstract 返回值类型 方法名(空参/带参) ;
- 抽象类的本质:
-
强制子类必须将父类的所有的抽象方法,必须实现(重写)
*抽象类的特点:
-
1)不能实例化(不能new 创建对象)
-
2)抽象类的子类一定有具体类,否则无法进行实例化的!
抽象abstract关键字不能和哪些关键字共存?
abstract不能和private共用:
被private修饰的只能在当前类访问,而abstract修饰的方法,它需要强制子类进行重写;
abstract不能和static共用:
abstract修饰的成员方法,需要被子类重写,还是抽象类多态进行实例化Fu fu = new Zi() ;
而static随着类的加载而加载(静态方法算不上重写),跟类相关的!
abstract不能和final共用:
被final修饰的成员方法不能被重写,而abstract修饰的成员方法,强转子类重写!
abstract:用在类上,标记这个类----抽象类
用在方法上,标记这个方法是一个抽象方法!
结合public使用居多
抽象的特点
抽象类的成员特点:
-
1)成员变量:
-
可以是变量也可以自定义的常量
-
2)成员方法
-
既可以有抽象方法,也可以有非抽象方法!
-
3)构造方法
-
还存在继承关系,分层初始化--->先父类构造初始化,然后是子类构造初始化!
-
无参构造方法/有参构造方法都可以存在,目的都是为了数据进行初始化!
有抽象类方法的类必须是抽象类
抽象类的方法不一定是抽类
接口Interface
体现的是这个事物本身不具备的功能 是一种额外扩展功能
interf {}
接口的子类(子实现类) implements
接口的方法只能是抽象方法
接口不能实例化
如何实例化
接口多态
接口名 对象名 =new 接口的子实现类
接口中所有变量都是常量 接口类隐藏了public fianl static
类与类 类与接口 接口和接口的关系
在Java中,
-
类与类:
-
继承关系,extends,而且只支持单继承,不支持多继承,但是可以多层继承!
-
类与接口
-
实现关系,implements,而且一个类继承另一个类的同时,是可以实现多个接口的!接口名和接口名直接逗号隔开
-
class LoverImpl extends Lover implements Love,Study{
-
接口与接口
-
继承关系,extends,不仅支持单继承,也支持多继承,也可以多层继承!
接口中的成员特点:
·
接口中的成员特点:
- 成员变量:只能是常量 存在默认修饰符 public static final
- 成员方法:(非静态):只能是抽象方法,存在默认修饰符 public abstract
- 在接口中是可以定义静态方法,必须有方法体(特例)
- 构造方法: 没有构造方法! 因为子实现类和接口的关系是implements实现关系,
- 只是将接口暴露的额外功能进行实现!
·
接口体现的是这个事物本身不具备的功能,是一种额外的扩展功能!
- 只要这个事物实现了接口,它就具备这个功能!
- 如何定义接口
-
java定义接口
-
interface 接口名{}
-
接口的子类(子实现类) implements 接口名{
-
强制子实现类必须将接口中所有抽象方法必须重写!(实现)
-
}
- 接口的特点:
-
1)接口不能实例化(不能创建对象)
-
2)接口如何实例化?
-
接口多态
-
接口名 对象名 = new 接口的子实现类名() ; (前提:子实现类是非抽象的,就是一个具体类)
*开发中:
- 接口名和子实现类的命名规范(开发项目中)
-
举例:
-
接口名: interface Inter{}
-
接口的子实现类命名: 接口名 +Impl
-
class InterImpl implements Inter{}
接口和抽象 的区别
区别:
1)成员的区别
抽象类:
成员变量:既可以常量(定义final修饰的),也可以是变量
成员方法:既可以存在抽象方法,而且也可以存在非抽象方法
如果定义抽象方法,abstract不能省略!
构造方法:存在,无参构造/有参构造方法,让类的数据进行初始化(构造初始化)
接口:
成员变量:只能是常量,存在隐藏的默认修饰符:public static final’
成员方法:只能是抽象方法
构造方法:没有
2)关系区别:
类与类:继承关系,只支持单继承,不支持多继承
类接口:实现关系,一个类继承另一个类的同时,可以实现多个接口
接口与接口:继承关系,可以单继承,也可以多继承以及多层继承
3)设计理念的区别
抽象类:有继承关系,抽象类不能创建对象,借助于抽象类多态(子类是具体类),进行实例化;
体现的核心思想: "is a"的关系
A类是B类的一种或者B类是A列的一种
水果:
橘子
香蕉
接口:体现的是事物的一种额外的扩展功能,本身不具备,需要实现接口才能具备这个功能!
体现的核心思想:
"like a"的关系
猫"跳高" -->
狗"做计算"—> 跳高以及做计算都是额外功能;
形参是具体类抽象类接口类
具体类:调用该方法,此时实际参数需要的是当前类的对象!
package com.qf.args_01;
/**
- 方法的形式参数问题: 只研究引用类型
-
方法形式参数:
-
具体类:调用该方法,此时实际参数需要的是当前类的对象!
*/
class Student{
public void studyJavaEE(){
System.out.println(“正在学习JavaEE之JavaSE”) ;
}
}
//定义一个StudentDemo类
class StudentDemo{
public void show(Student s){//方法的形式参数是一个学生类型
s.studyJavaEE() ;
}
}
//测试类
public class ArgsDemo1 {
public static void main(String[] args) {
//访问StudentDemo类中的show方法
StudentDemo sd = new StudentDemo() ;
Student student = new Student() ;
sd.show(student) ;
System.out.println(“----------------------”) ;
//另一种方式:匿名对象
new StudentDemo().show(new Student());
}
}
抽象类:调用该方法,此时实际参数需要的是当前抽象类的子类对象!
package com.qf.args_01;
/**
- 方法的形式参数问题: 只研究引用类型
-
方法形式参数:
-
抽象类:调用该方法,此时实际参数需要的是当前抽象类的子类对象!
*/
//定义一个Person类
abstract class Person{
/public void work(){
System.out.println(“人都需要工作”);
}/
public abstract void work() ;
}
//定义一个PersonDemo类
class PersonDemo{
public void function(Person p){//方法的形式参数是引用类型–抽象类,抽象类不能new,需要传递抽象类的子类对象!
p.work() ;
}
}
//定义抽象类的子类(具体类)
class Worker extends Person{
@Override
public void work() {
System.out.println(“爱工作,爱Java,爱高圆圆!”);
}
}
//测试类
public class ArgsDemo2 {
public static void main(String[] args) {
//访问PersonDemo类中的function方法?
PersonDemo pd = new PersonDemo() ;
//Person p = new Person() ;抽象类不能实例化(不能创建对象)
Person p = new Worker() ;
pd.function§ ;
System.out.println(“-----------------------”) ;
new PersonDemo().function(new Worker());
}
}
接口类型:调用该方法,此时实际参数需要的是接口的子实现类对象!
package com.qf.args_01;
/**
- 方法的形式参数问题: 只研究引用类型
-
方法形式参数:
-
接口类型:调用该方法,此时实际参数需要的是接口的子实现类对象!
-
开发中:方法形式参数是具体类以及接口情况居多的!
*/
//定义一个接口
interface Love{
public abstract void love() ;
}
//定义一个类:LoveDemo
class LoveDemo{
public void method(Love l) {//方法的形式参数是一个接口? 接口不能new,需要接口的子实现类对象
l.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()) ;
}
}
开发中:方法形式参数是具体类以及接口情况居多的!
返回值是具体类抽象类接口类
具体类:需要返回该具体类的对象!
package com.qf.return_02;
/**
- 方法的返回值问题:
-
要么基本类型/引用数据类型
-
基本类型:简单,要什么类型,使用指定的类型接收即可!
-
研究的方法的返回值引用类型:
-
方法的返回值如果是引用类型:
-
具体类:需要返回该具体类的对象!
-
抽象类:
-
接口:
*/
class Demo{
//对两个数据求和
public int sum(int a,int b){
return a+ b;
}
}
//定义学生类
class Student{
public void study(){
System.out.println(“好好学习,天天向上!”);
}
}
//StudentDemo类
class StudentDemo{
public Student show(){
//return Student ; 错误
//方式1:
// Student s = new Student() ;
//return s ;
//方式2:匿名对象
return new Student() ;
}
}
//测试类
public class ReturnDemo1 {
public static void main(String[] args) {
Demo d = new Demo() ;
int result = d.sum(10, 15);
System.out.println(result);
System.out.println(“--------------------”);
//访问StudentDemo类中的方法
StudentDemo sd = new StudentDemo() ;
Student student = sd.show(); //show方法就是new Student()
student.study();
}
}
抽象类:需要返回该抽象类的子类对象!
package com.qf.return_02;
/**
-
研究的方法的返回值引用类型:
-
方法的返回值如果是引用类型:
-
具体类:需要返回该具体类的对象!
-
抽象类:需要返回该抽象类的子类对象!
-
接口:
*/
//定义一个Person类
abstract class Person{
public abstract void work() ;
}
//PersonDemo类
class PersonDemo{
public Person function(){//方法的返回值是一个抽象类
//?
// return new Person() ; 抽象类不能实例化
//方式1:抽象类多态
//Person p = new Programmer() ;
//return p;
//方式2:直接匿名对象 (创建子类对象)
return new Programmer() ;
}
}
//定义一个类,继承Person
//程序员
class Programmer extends Person{
@Override
public void work() {
System.out.println(“程序员日日夜夜敲代码!”);
}
}
//测试类
public class ReturnDemo2 {
public static void main(String[] args) {
//访问PersonDemo类的function方法
PersonDemo pd = new PersonDemo() ;
Person person = pd.function(); //funciton方法 本质—>创建了子类对象
person.work();
}
}
接口类型:需要返回接口子实现类对象!
package com.qf.return_02;
import sun.util.resources.ms.CalendarData_ms_MY;
/**
-
研究的方法的返回值引用类型:
-
方法的返回值如果是引用类型:
-
具体类:需要返回该具体类的对象!
-
抽象类:需要返回该抽象类的子类对象!
-
接口:需要返回接口子实现类对象!
*/
//定义一个接口
interface Mary{ //结婚的接口
public abstract void mary() ;
}
//定义一个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 mary() {
System.out.println(“要结婚了,很开心…”);
}
}
//测试类
public class ReturnDemo3 {
public static void main(String[] args) {
//需求:访问MaryDemo类中的method方法?
MaryDemo md = new MaryDemo() ;
Mary mary = md.method();
mary.mary();
System.out.println(“-----------------------”);
Mary mary2 = new MaryDemo().method();
mary2.mary();
}
}
包的含义和代码分层(了解)
包—package存储本地Java代码的一个目录(文件夹)
net.qf.pojo//pojo是指存储的实体类(描述现实世界事物的)
net.qf.service//存储的业务接口
impl: 以及业务实现:具体业务实现过程的代码
net.qf.dao// dao(数据访问层:Data Access Object:数据访问对象):数据访问接口
net.qf.utils//utils:工具类–>存储的都是通用的工具类的代码 xxx.java文件
net.qf.test//test:存储的测试接口中的功能代码
权限修饰符
private 私有
(默认修饰符)
proteed 受保护的
public 公开的
同一个包下的同一个类 | 同一个包下的子类/同一个包下的无关类 | 不同包下的子类 | 不同包下的无关类 | |
---|---|---|---|---|
private/私有 | yes | |||
默认修饰符 | yes | yes | ||
protected/受保护的 | yes | yes | yes | |
public/公开的 | yes | yes | yes | yes |
private私有修饰符权限最小
instanceof 判断对象名是否为后面这个类型的实例
内部类
java中一个类中定义另一个类:类A中定义类B 。B是A的内部类。A是B的外部类
分类
成员内部类
在外部类中外部类方法外定义的类
可以访问外部类的成员(包括私有)
创建外部类对象,访问外部类的成员方法 间接调用了成员内部类的成员方法
测试类中直接调用内部类成员方法:
适用非静态成员内部类
外部类名.内部类名 对象名=new 外部类名().new 内部类名()
成员内部类可以使用static修饰
特点
静态的成员内部类的所有成员方法,无论静态还是非静态。访问外部类的成员必须先为静态
测试类中直接调用内部类成员方法:
适用静态成员内部类
外部类名.内部类名 对象名=new 外部类名.内部类名();
局部内部类
方法定义中定义的类也是可以访问外部类的成员变量(包括私有)
创建局部内部类的对象就可以访问局部类的方法
JDK8以前 局部内部类访问(外部类成员方法中的)局部变量会报错 需要给局部变量加final才行;
面试题
局部内部类的成员访问局部变量的时候 局部变量有何要求
局部变量的生命周期随着方法的调用而存在,随着方法的调用结束而消失
外部类的成员方法调用完毕之后,此时的局部变量释放了,成员方法中创建了局部内部类对象去访问他的成员方法,间接使用。所以显示加入final 修饰局部变量
匿名内部类:针对抽象类或者接口去使用、
new 类名/接口名(){}
重写类或者接口的抽象功能};
| **同一个包下的同一个类** | **同一个包下的子类/同一个包下的无关类** | **不同包下的子类** | **不同包下的无关类** |
| ------------------ | ------------------------ | --------------------------------------- | ------------------ | -------------------- |
| private/私有 | yes | | | |
| 默认修饰符 | yes | yes | | |
| protected/受保护的 | yes | yes | yes | |
| public/公开的 | yes | yes | yes | yes |
private私有修饰符权限最小
instanceof 判断对象名是否为后面这个类型的实例
内部类
java中一个类中定义另一个类:类A中定义类B 。B是A的内部类。A是B的外部类
分类
成员内部类
在外部类中外部类方法外定义的类
可以访问外部类的成员(包括私有)
创建外部类对象,访问外部类的成员方法 间接调用了成员内部类的成员方法
测试类中直接调用内部类成员方法:
适用非静态成员内部类
外部类名.内部类名 对象名=new 外部类名().new 内部类名()
成员内部类可以使用static修饰
特点
静态的成员内部类的所有成员方法,无论静态还是非静态。访问外部类的成员必须先为静态
测试类中直接调用内部类成员方法:
适用静态成员内部类
外部类名.内部类名 对象名=new 外部类名.内部类名();
局部内部类
方法定义中定义的类也是可以访问外部类的成员变量(包括私有)
创建局部内部类的对象就可以访问局部类的方法
JDK8以前 局部内部类访问(外部类成员方法中的)局部变量会报错 需要给局部变量加final才行;
面试题
局部内部类的成员访问局部变量的时候 局部变量有何要求
局部变量的生命周期随着方法的调用而存在,随着方法的调用结束而消失
外部类的成员方法调用完毕之后,此时的局部变量释放了,成员方法中创建了局部内部类对象去访问他的成员方法,间接使用。所以显示加入final 修饰局部变量
匿名内部类:针对抽象类或者接口去使用、
new 类名/接口名(){}
重写类或者接口的抽象功能};
范围:局部位置中使用本质:继承了该抽象类或者实现了该接口的子实现类