1.类中的内存图解(创建一个对象/创建对个对象)
1.1创建一个对象的内存图解
创建对象时,会在堆内存中开辟出一块内存区,用来存放类中的的成员方法,以及初始化成员方法.而栈内存中只是对象在堆内存中的地址值.
1.2创建多个对象的内存图解
创建对象时创建的是对象的地址值,然后用对象名.变量名来给变量赋值,从而改变变量的值,多个对象之间传递的也是地址值.
2.局部变量和成员变量的区别
1)定义的位置不同:
成员变量:在内中方法外定义;
局部变量:在方法声明上或者方法内定义;
public void show(String name){ //在方法上声明上定义局部变量;
int num = 200 ; //在方法内定义局部变量;
System.out.println(name+num) ;
}
2)内存位置不同:
成员变量:在堆内存中
局部变量:在栈内存中
3)生命周期不一样:
成员变量:随着对象的创建而存在,随着对象被GC回收而消失
对象的回收:并不是立即回收而是等垃圾回收器空闲时候回收;
局部变量:随着方法的调用而存在,方法调用完毕而消失;
4)初始化的情况不一样:
成员变量:可以不用进行初始化,因为在堆内存中,存在系统默认初始化;
局部变量:在使用前必须要对变量进行初始化;
3.面向对象三大特征-------封装
3.1封装的概念
将一个类中的成员变量私有化(使用private修饰),外界不能直接访问变量,可以通过一些公共的方法(set/get)间接的访问
3.2封装中的关键字
private:私有的
外界不能直接访问,只能在本类中访问,可以修饰成员变量,也可以修饰成员方法;
this:
代表当前类对象的地址值引用;为了区分局部变量隐藏成员变量的情况---->this.成员变量;
3.3代码体现
public class Demo3 {
//成员变量私有化
private String name;
private int age;
private String geder;
//公共访问方法(setXxx ---->赋值/getXxx---->调用)
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 getGeder() {
return geder;
}
public void setGeder(String geder) {
this.geder = geder;
}
}
4.匿名对象
匿名对象:
概念:没有名字的对象!
之前的格式:
类名 对象名 = new 类名() ;
匿名对象的创建格式:
new 类名() ;
特点:
1)可以作为形式参数传递!
2)匿名对象不要使用多次,使用一次即可!
匿名对象创建完毕,使用完毕就立即被回收(节省内存空间)
4.1代码体现
//有一个学生类
class Student{
public void love(){
System.out.println("爱学习,爱Java...") ;
}
}
//定义一个类:StudentDemo
class StudentDemo{
public void method(Student s){
s.love() ;
}
}
//测试类
class NoNameDemo{
public static void main(String[] args){
//需求:需要访问StudentDemo类中的method方法
StudentDemo sd = new StudentDemo();
Student student = new Student() ;
sd.method(student) ;
System.out.println("----------------------") ;
/*
匿名对象的创建格式:
new 类名() ;
*/
需求:需要访问StudentDemo类中的method方法
StudentDemo sd2 = new StudentDemo();
sd2.method(new Student()) ;
System.out.println("----------------------") ;
//链式编程:非正式
//需求:需要访问StudentDemo类中的method方法
new StudentDemo().method(new Student()) ;
}
}
5.构造方法
5.1什么是构造方法
特点:
1)方法名和类名相同
2)没有具体的返回值类型
3)连void都没有
权限修饰符 方法名和类名相同(){ //无参构造方法
}
构造方法的作用:给对象的成员进行数据初始化的!
构造方法:
构造方法是可以重载的:
无参构造方法
有参构造方法
注意事项:
在写一个类的时候,没有提供无参构造方法,系统默认提供无参构造方法!
如果开发者提供有参构造方法,系统不会提供无参构造方法了,所以永远给出无参构造方法!
5.2代码体现
class Student{
//成员变量私有化
private String name ; //姓名
private int age ; //年龄
private String gender ; //性别
//构造方法:
//无参构造
public Student(){
}
//有参构造方法赋值
public Student(String name,int age,String gender){ //"张三",30,"男"
this.name = name ;
this.age = age ;
this.gender = gender;
}
6.一个标准类的写法
包含的内容:成员变量(私有化),无参构造,有参构造,set/get方法,成员方法.
6.1代码体现
class Student{
private String name ; //姓名
private int age ; //年龄
private String gender ; //性别
//构造方法:
//无参构造
public Student(){
}
//有参构造方法赋值
public Student(String name,int age,String gender){ //"张三",30,"女"
this.name = name ;
this.age = age ;
this.gender = gender;
}
//公共的访问方法
//setXXX方法
//给姓名赋值
public void setName(String name){
this.name = name ;
}
//年龄赋值
public void setAge(int age){
this.age = age ;
}
//给性别赋值
public void setGender(String gender){
this.gender = gender ;
}
//获取成员变量信息
public String getName(){
return name ;
}
public int getAge(){
return age ;
}
public String getGender(){
return gender ;
}
//学习
public void study(){
System.out.println("正在学习标准类的写法格式...") ;
}
//玩游戏
public void playGame(){
System.out.println("学习累了可以玩把王者农药!!") ;
}
}
//测试类
class StudentTest{
public static void main(String[] args){
//两种方式
//方式1:无参构造方法+setXXX(xxx) + getXXX()
Student s1 = new Student() ;
s1.setName("李四") ;
s1.setAge(35) ;
s1.setGender("男") ;
System.out.println(s1.getName()+"---"+s1.getAge()+"---"+s1.getGender());
s1.study();
s1.playGame() ;
System.out.println("---------------------------------");
//方式2:通过有参构造方法直接赋值+getXXX()
Student s2 = new Student("张三",30,"女") ;
System.out.println(s2.getName()+"---"+s2.getAge()+"---"+s2.getGender());
s2.study();
s2.playGame() ;
}
}
7.代码块
Java中代码块:
使用{}包起来的内容,就称为代码块!
分类:
1)局部代码块
在局部位置中定义的{},作用:限定变量的声明周期
2)构造代码块
在类的成员位置中定义{},
特点:在当前类中,有优先执行构造代码块,然后在执行构造方法...
(每次执行构造方法之前先执行构造代码块)
构造代码块的作用:对当前类的数据进行初始化!(很少用,笔试题!)
3)静态代码块
在{}的前面加上static
static{
....
}
静态代码块随着的类的加载而加载,由于类加载一次,静态代码块执行一次!
优先级:
静态代码块 > 构造代码块 >构造方法
7.1代码体现
//定义一个Code类
class Code{
//静态代码块
static{
int x = 1000;
System.out.println(x) ;
}
//构造构造方法
public Code(){
System.out.println("code...") ;
}
//成员位置
//构造代码块
{
int x = 100;
System.out.println(x) ;
}
//有参构造方法
public Code(int num){
System.out.println("code"+num) ;
}
//构造代码块
{
int y = 200 ;
System.out.println(y) ;
}
static{
int y =2000;
System.out.println(y) ;
}
}
class CodeDemo{
public static void main(String[] args){
//定义一个变量x
int x = 10 ;
System.out.println(x) ; //10
//局部位置
//局部代码块
{
int y = 100 ;
System.out.println(y) ;
}
//System.out.println(y) ; 找不到符号
System.out.println("---------------------------") ;
//创建Code对象
Code c1 = new Code() ;
System.out.println("---------------------------") ;
Code c2 = new Code(100) ;
}
}
运行结果:
10
100
---------------------------
1000
2000
100
200
code...
---------------------------
100
200
code100
8.面向对象三大特征-------继承(extends)
8.1概念:
将多个类中的共性抽取出来单独的定义在一个类里面,让这个独立的类和多个类产生一种关系即为继承关系(extends)
8.2优点:
1)提高代码的复用性;
2)提高代码的维护性;
3) 类与类之间的继承关系是多态的前提条件;
8.3特点:
在java中不支持一个类同时继承多个类,只支持单独继承同时继承一个类,但是可以多层继承;
8.4继承中注意的事项:
1)子类继承父类时不能继承父类的私有成员(成员变量,成员方法);因为被私有化的成员只能在本类中访问,外界访问不到,只能通过公关方法访问;
2)子类继承父类的时候不能继承父类的构造方法,但是可以通过super()间接访问;
注:子类的所有构造方法都默认访问父类的无参构造方法.
目的:为了先让数据初始化.由于存在继承关系,创建的是之类的对象,对子类初始化的时候(执行构造方法),可能会用到父类的数据,必须要让父类进行初始化(先执行父类的构造方法),父类初始化完毕,子类才进行初始化.
每一个子类的构造方法第一句都会默认有一句super();
super():代表父类的空间标识符(代表父类对象的地址引用);
this:代表当前类的对象地引用;
8.5继承中的一些情况
8.5.1关于继承中子类和父类成员变量一致的情况
现在子类的局部位置中找------>子类的成员位置找----->父类的成员位置找------>找不到就报错;
成员方法:
成员方法名不一致:分别访问即可;
成员方法名一致的情况:现在子类中找是否有这个方法,有就用,会将父类中的方法覆盖掉------>子类中找不到就在父类中找------>找不到就报错;
8.8.2方法重载(OverLoad)和方法重写(Override)
方法重载:方法名相同,参数列表不同,与返回值无关的方法;
方法重写:子类继承父类,子类中出现了和父类一样的方法;
注:在子类重写父类中,要保证子类的访问权限比父类大;
关于访问权限的修饰符在不同情况下的访问权限问题
8.8.3如果父类中没有提供无参构造方法怎么办?
1)手动给出父类的无参构造;
2)可以让子类的所有构造方法都默认访问父类的有参构造方法,,在子类的构造方法的第一句加上
super(xxx);
3)通过子类的有参构造方法访问this()本类中的无参构造方法,在通过本类的无参构造方法访问父类的有参构造
9.面向对象三大特征------多态
9.1多态的概念
一个事物在不同时刻显示出的不同状态(在堆内存中的变化);
比如水在不同情况下为不同的状态,液体,固体,气体
9.2多态的前提条件
1)必须存在继承关系;
2)要有方法重写;
3)需要存在父类引用指向子类对象(向上转型);
父类名 对象名 = new 子类名;
9.3多态成员的访问特点
父类名 子类名 = new 子类名();
1)成员变量:编译看左,运行看左;
2)成员方法(非静态):编译看左,运行看右(存在子类覆盖父类的方法:方法重写);
3)静态成员方法:编译看左,运行看左(静态方法跟类相关,不存在重写);
4)构造方法:由于存在继承关系,还需要分层初始化;
9.4多态的优劣
优点:
1)提高代码的扩展性(由多态保证);
2)提高代码的复用性和维护性(由继承保证);
缺点:
1)不能访问子类的特有功能;
解决办法:
1)创建子类的对象: Zi z =new Zi();----------->方法可行,但是浪费堆内存空间;
2) 多态的第三个条件:为父类指向子类(向上转型);
将父类的引用强制转换为子类的引用(向下转型)(前提必须要有向上转型);
格式: Zi z =(Zi) f ;--------------f指的是父类指向值时创建的对象名;
10.抽象类
10.1概念
一个没有方法体的方法定义为抽象方法,含有抽象方法的类为抽象类.
在一个类中,将某个功能给出一个声明那么该类定义为抽象类;
抽象类中可以没有抽象方法,但是有抽象方法的类一定是抽象类;
关键字: abstract ---->修饰类,方法;抽象的意思
抽象方法的定义格式: 权限修饰符 abstract 返回值类型 方法名 () ;
抽象类中没有抽象方法的目的:让当前类无法被直接实例化;
10.2抽象类的注意事项
1)如果一个类中有抽象方法,那么这个类一定是抽象类,但是抽象类中还可以有非抽象方法.
2)抽象类不能直接实例化(创建对象),要通过具体的子类实例化(通过多台实现);
格式: 父类名 对象名 = new 子类名();
3)抽象类的子类:
子类要么是具体类,要么是抽象类;
子类是具体类,直接可以是抽象类多态的形式实现;
子类是抽象类,应该还要提供更具体的子类,否则都无法实例化;
4)在抽象类中定义抽象方法时抽象方法必须带上abstract;
10.3 abstract使用时的注意使用事项
abstract不能和以下关键字同时使用
final: final修饰成员方法不能被重写,但是abstract修饰的方法强制重写,有冲突;
private: private只能本类访问;
static: 被static修饰的可以被类调用,但是抽象类无方法体要让子类重写;
11.接口
11.1概念
是描述一个事物的扩展功能,本身事物不具备的,如果该事物想使用这个扩展功能,必须用接口的功能进行实现;
定义:
interface 接口名{
接口中的方法;
}
接口中的方法只能是抽象方法,不能存在具体方法.
接口的实现和接口是一种实现关系----->implements;
将接口的实现类称为接口的子实现类;
接口与接口之间可以单继承,也可以多继承;
11.2接口的实例化
接口不能直接实例化;
格式:
接口名 对象名 = new 子实现类名(); //接口多态
11.3接口的成员特点:
成员变量: 只能为静态常量;存在默认修饰符 public static final.....
成员方法:接口中的方法只能是抽象方法;存在默认修饰符 public abstract...;
构造方法:没有构造方法;
11.4抽象类和接口的区别
1)成员的区别:
抽象类: 成员变量:既可以是抽象类也可以是非抽象类;
成员方法:既可以定义常量,也可以定义变量;
构造方法:存在构造方法对数据进行初始化;
接口: 成员变量:只能是一个常量,存在默认修饰符;
成员方法:只能是抽象类;
不存在构造方法;
2)关系的区别:
类与类之间:extends
继承关系,只支持单继承,但可以多层继承;
类与接口之间:implements
实现关系,一个类在继承一个类的时候可以实现多个接口;
接口与接口之间:extends
继承关系,可以单继承也可以多继承.
3)设计理念的区别:
抽象类:由继承来保证代码的复用性,由多态来保证代码的扩展性,体现一种"is a"的关系;
接口:是一种扩展功能,体现的是一种"like a" 的关系
12.内部类
12.1内部类
在一个类中定义另一个类,内部类可以直接访问外部类的成员包括私有成员.(不含静态);内部类与外部类之间无法继承.
1)成员内部类:
在类的成员位置定义的类
访问格式:
外部类名.内部类名 对象名 = 外部类对象.内部类对象;
2)局部内部类:
在方法定义中定义的类(局部位置)
如果成员内部类是一个静态的,通过外部类访问静态成员内部类的成员方法
访问格式:
外部类名.内部类名 对象名 = new 外部类名.内部类名(;)
12.2匿名内部类
是内部类的一种简化格式,没有具体的类名;
格式:
new 类名(抽象类名/接口){
重写方法;
}
匿名内部类的本质就是继承该抽象类或者实现该接口的子实现类对象.