Day07:
1.如果局部变量和全局变量都有相同的数据类型和变量名,先调用局部变量,实现就近原则;
2.匿名对象由于局限性的原因,一般只调用一次,且只是当作为实际参数传递的时候使用;
3.面向对象语言的三大基本特征:封装,继承,多态
4.封装的好处:安全,方便,用private(只能在本类中访问)体现;
5.构造函数是为了显示初始化;是没有返回值类型的
6.在构造函数可以调用一般函数,但是在一般函数中不可以调用构造函数;
7.构造函数定义的细节:
1、构造函数是用来创建对象的,它不需要书写返回值类型。
2、构造函数的名字要求必须和当前的类名一致。因此构造函数的名称书写和类名一致。
3、参数列表,可以和一般函数的参数列表一样。
8.构造函数的作用:就是为了给对象初始化时使用的。(就是为了给非静态成员变量初始化值使用)。
9.在new的类中,只要写了构造函数,编译器就不会自动添加无参构造。所以参数列表必须得一样,不然报错。如果没有写构造方法,那么编译器在编译的时候会自动添加一个无参构造方法(这个方法称为默认无参构造函数);
10.构造方法可以以重载的方式存在同一个类中;
11.构造函数和一般函数异同
1、它们的执行时间不同:
构造函数是在创建对象的过程中执行。当对象创建完成了,构造函数就已经执行结束。
一般函数执行时间有两种情况:
1) 如果调用其他类中的函数时:一般函数通过是在对象创建完成之后,通过对象的引用来调用。
2) 如果调用本类中的函数时:什么时候使用,什么时候调用。
2、它们的调用次数不同:
构造函数只有在new对象的时候,会被调用,一旦对象创建完成,我们不能手动的人为去调用构造函数。
一般函数可以通过对象随意的调用,没有次数限制。
3、它们互相调用问题:
在构造函数中可以去调用一般的函数,但是在一般的函数中不能调用构造函数。
(构造函数和一般函数的区别:
1. 构造函数没有返回值类型,而一般函数的有返回值类型;
2. 构造函数只有在新建对象的时候才会使用,因为新建而存在,随着新建的结束而消失,不能随意的调用;而一般函数可以在同一个类或者不同类中存在,调用次数不限,如果在同一个类中定义则可以通过函数名直接调用;如果在不同类中定义,则调用的时候需要通过对象名调用;随着调用而存在,随着方法的结束而消失;
3. 互相调用问题:构造函数可以调用一般函数,而一般函数不可以调用构造函数;)
12.怎么使用this来调用其它的构造函数?
this调用其它构造函数的格式: this(参数列表); //相当于 构造函数(参数列表)
在Java中只要是通过名称调用函数,那么调用的都是一般函数,构造函数之间不能通过函数名调用。
12.在使用this调用构造函数的时候注意的问题:
1、构造函数之间不能相互嵌套调用,这样就会导致无限制的调用构造函数,导致永远无法停止调用。
2、this调用构造函数,必须放在构造函数中的第一句。我们通过this调用构造函数的目的是希望通过其他的构造函数完成初始化动作,因此要求其他构造函数的初始化必须在本构造函数中语句执行之前先初始化完成。
13.this的第二个功能:在构造方法或者通过对象名调用类中方法的时候,语句中是有隐藏this变量,此时的this保存的就是谁调用,就是谁在堆内存中new的地址名,所以可以访问到new完之后堆内存里的成员变量的值;
14.this的第三个功能是区分成员变量和局部变量,谁调用,this就代表谁;
想使用this,必须有对象,因为this记住的是对象在堆内存产生的地址名
Day08:
1.每个类都有默认的无参构造函数;
2.对new出来的对象类执行流程,先执行静态代码块(以后会经常使用,主要是为了初始化静态成员变量,另外静态代码块只会执行一次),如果多个就从上往下执行;对于调用构造函数的时候有隐式三步(1. Super(),2.对成员变量显示初始化,3.执行构造代码块),如果有多个构造代码块,则也是按照上下顺序依次执行;
3.静态函数中不能有非静态成员变量和非静态成员函数;而非静态成员函数中可以有静态成员变量和静态函数;
4.Static修饰的成员变量和成员函数在其他类中可以通过类名和对象名调用,与对象无关,主要和类有关,随着类的加载而执行和加载;而非静态函数和非静态成员变量在其他类中只可以通过对象调用;
5.静态成员变量和非静态成员变量的区别:
a.创建的时间不同,静态的会随着类的加载而加载,而非静态的会随着对象的创建而加载;
b.在内存的位置不同,静态的会是在类加载的方法区中的静态区加载,而非静态的会是在对象的创建在堆内存中加载;
c.在内存中的消失时间不同,静态的只有当JVM退出的时候才会消失,而非静态的会随着对象的消失而消失;
d.初始化的时间不同,静态变量会随着类的加载而加载,会当时就赋值初始化了,而非静态的则随着对象的创建才被初始化赋值;
6.在类加载的时候,JVM会先加载类中的所有静态成员变量,当把所有的静态成员变量加载完成之后,开始给类中的所有静态成员变量进行默认初始化,当类中的所有静态成员变量默认初始化完之后,会接着开始给所有静态成员变量进行显示的赋值操作。只有类中所有的静态成员变量显示赋值结束之后,静态代码块才会运行。
小结:
1、静态代码块随着类的加载而执行,仅执行一次
2、静态代码块的作用:给类进行初始化。
7.构造函数的隐式的三步:a. super() ; b. 成员变量显示初始化 ; c .构造代码块执行
8.类的加载过程:
a.首先在方法区中加载类的class文件到非静态区,然后将静态的成员变量,静态成员方法和静态代码块加载到静态区;
b.所有的静态加载完成后再将静态成员变量进行一步步的默认初始化,然后再进行显示初始化;
c.静态成员变量显示初始化完成后再运行静态代码块;
d.所有的静态代码块加载完成后才代表整个类的加载完成;
创建对象的加载过程:
a.使用关键字new创建对象,会在堆内存中开辟空间并随机分配地址名;
b.在开辟的空间中会将所有的非静态成员变量加载到堆内存分配空间,进行默认初始化;
c.加载完成后会调用匹配的构造函数:(隐式三步)1.super();2.将所有的非静态成员变量进行显示初始化;3.运行构造代码块;最后运行构造函数的其他代码;
d.构造函数执行完成,对象创建完毕;
9.单例设计模式:
A.为了实现只能创建一个对象,所以要把所有的构造函数都得私有化,不能让其他类调用;
B.构造函数私有化了,那么只能自己在内部进行对象的创建;
C.同时需要一个对外的函数实现返回已创建的对象,但是由于其他类不能创建新对象,所以调用函数不能通过对象名调用,只能是类名调用,所以这个函数必须得是静态的,那么return的对象也得是静态的;
D.这样就能通过类名来调用函数返回给调用者创建的对象;
E.但是上述的创建过程还有一个漏洞,就是创建新对象的表达式没有被私有化,虽然静态修饰了,但是还是能通过类名进行调用,这样不符合要求,所以创建新对象的表达式也得被私有化,这样外部就访问不到,创建不了其他新对象了。
F.完美的实现了单例设计模式
Day09:
1.static修饰的函数里面不能有this,super,因为this记住的是对象的地址名,和对象有关,super是调用了父类的构造函数,构造函数也是和对象有关,所以不可以;
2.this和super的区别:
1) this表示的本类中的成员,super表示父类中的成员。
2) 在Java中,this是一个引用变量,它中保存的是当前调用这个函数的那个对象的内存地址。
super仅仅表示的父类的内存空间。但不是父类的对象。super仅仅只是一个标记,标记哪个是父类。
3) this表示子类对象在堆中开辟的整个空间,而super标记的是子类对象开辟空间中的父类所占的空间。
注意:在开发中,通常父类中已经定义了成员变量,子类在继承后直接使用就可以了,不需要再次定义新的成员变量。
3.方法(函数)的特点:
函数重载(overload): 发生在同一个类中
方法名相同、参数列表不相同。和返回值没有关系
函数重写(override): 发生在子父类中
方法名相同、参数列表相同、返回值类型相同 (子父类中的方法一模一样)
4.子类在复写父类的函数时,子类的方法访问权限,必须大于等于父类的权限。父类中被private修饰的成员变量和成员函数不能被调用和重写;
5.被final修饰的变量编译后为常量,且变量名必须大写,以示区分;
6.抽象函数的方法,子类就一定得复写所有的抽象函数,且抽象函数一定得用abstract修饰.
7.一旦某个类中有了抽象的函数这个类就变成抽象类了。同样的类名也需要abstract修饰,重点是该抽象函数不能有方法体;
8.接口的默认修饰符是public abstract,所以重写接口的实现函数的修饰符一定得是public
9.final小结:
1) 被final修饰的成员变量,编译后变为常量,不能修改其值;
2) 被final修饰的成员函数,不能被子类方法重写;
3) 被final修饰的类,不能被子类继承;
4) final它可以修饰类,可以修饰成员(成员变量、成员函数),修饰局部变量。不能修饰构造函数;
10.抽象类被继承抽象函数必须得复写,有抽象函数的类就是必须的抽象类;但是抽象类里不一定就一定有抽象函数;
11.子类想调用父类函数,必须在复写的子类函数体中写super.函数名();
12.抽象类一定有子类,但要是没有子类编译也不会报错,也有父类,至少是Object类;抽象类无法被创建对象,不能实例化;必须有子类实现,抽象函数必须被复写;如果抽象类能够创建对象,那么这个对象就可以调用抽象函数,但是抽象函数没有方法体,没有任何意义;
13.接口中的成员变量默认修饰符为:public static final ,且变量名字母大写;想调用就用接口名.变量名;
Day10:
1.接口中只能有成员变量和成员函数
2.在实现接口的类中调用接口中的成员变量就可以直接写变量名,属于有点继承的关系;但是测试类想用就得是接口名.变量名调用;
3.如果接口里的函数有不重写会报错吗?会,实现了某个接口必须复写接口中的所有函数
4.如果一个类实现了多个接口,且多个接口中有同个函数,那这个类复写同样的函数时就只需要复写一次就可以,因为函数都是没有函数体,所有就不会有不确定性;
5.如果一个类实现了多个接口,且多个接口中有同个成员变量,那调用的时候得是接口名.变量名,不然编译出错,因为有不确定性;
6.敲代码:适配器代码,设计模式的思想为定义一个抽象类,复写接口内的所有方法,但是函数体是空的,这样调用和复写起来就比较方便。但是适配器得是抽象的,因为不是抽象的没啥意义;
7.适配器为什么是抽象类?因为不是抽象函数就能创建子类对象,但适配器里的函数都是空函数体的,就算创建了对象,调用函数没有任何意义;其实abstract可以不写,但是菜鸟;
8.抽象函数的返回值只能的void吗? 不是,也可以是其他类型,看具体的需求。
9.多态能发生在接口中吗?/////////接口被实例化对象实现,是可以使用(接口名 对象名= new 实现类名()),这样对象名可以调用实现类中的函数,类似于多态;
/*
这个就用了接口传参,用实现类对象做实参,也是发生了多态,调用了实现类对象的函数;所以多态也是可以发生在接口中
*/
9.抽象类也可以实现多态,编译和运行的规则和一般类一样;
10.使用多态场景有:如果父类中的成员函数较多,且子类都想调用,那可以将子类名调用函数的方法体都提出取来,传参为父类类型。其他子类的特有函数可以使用instanceof关键字判断,然后使用强制转型进行向下转型;
11.多态弊端总结:
在使用多态技术的时候,程序在编译的时候,使用多态调用成员(变量和函数),要求被调用的成员在父类中一定要存在,如果父类中没有编译就会失败。(不能使用子类特有功能或者属性)
注意:只要有多态的地方,一定发生类型的提升(肯定是把子类对象使用父类类型在表示)。
1)什么时候使用向下转型:
只要在程序中我们需要使用子类的特有属性或行为(方法、函数)的时候,才会使用向下转型。
2)无论是向上还是向下转型,最终都是子类对象做着类型的变化。和父类对象没有关系。
12.总结:
只要有多态,就会有类型的转换。
把子类对象赋值给父类的引用,这时发生了向上的转型(隐式类型转换)。
如果我们需要使用子类的特有行为或属性,这时必须向下转型,需要把父类的引用转成具体所指的那个对象的类型。
在向下转型的时候一定要做类型的判断,防止ClassCastException异常的发生。
判断格式:
if( 父类引用变量名 instanceOf 子类对象所属的类名 )
{
进行转换。
}
13.总结多态中成员使用规律:成员变量和静态成员函数,编译运行都看左边(父类中的)。只有非静态成员函数,编译看父类,运行看子类对象。
14.个人总结抽象类和接口的区别:
a.接口里只能写成员变量和函数,且函数是抽象函数,默认修饰符为public abstract,变量的默认修饰符是public static final即变量变成了常量,必须得有初始化值;抽象类里可以写成员变量和成员函数(包括静态和非静态),有构造函数(为了给子类变量初始化但不能创建对象),可以有静态代码块,成员函数可以是抽象或者是非抽象的,不一定必须得有抽象函数;
b.接口必须得实现,且实现类里必须重写接口里的函数(注意函数修饰符的权限大小问题);抽象函数不一定得继承,可以不被继承,但是一旦被继承了,那么继承类必须重写抽象函数;(注:一旦有抽象函数,那么这个类一定是抽象类)
c.接口是表示某些事物的额外功能;抽象类里的抽象函数则是表示类中的行为不能全部描述,所以写成抽象函数;
d.接口的实现用关键字implements;抽象类被继承的关键字为extends;
e.接口是可以多实现,接口之间可以多继承;而抽象类和类只能单继承;
f.抽象类关键字不和private、static、final修饰符共存
Day11:
1.成员内部类:
Public修饰:
a.创建对象可以在外部类中创建,Inner in = new Inner();(隐藏意思:Outer.Inner in = new Outer.Inner();)然后放在外部类的函数里,这样在其他类中创建外部类的对象,在调用函数,就能调用内部类的函数
b.创建内部类对象可以在其他类中,这样可以通过外部类对象调用创建内部类:Outer o = new Outer(); Outer.Inner in = o.new Inner();换成一行代码为:Outer.Inner in = new Outer().new Inner();
如果我们想要在其他类中调用内部类中的一般函数(非静态函数),必须要使用内部类的对象来调用,所以我们要创建内部类的对象,创建方式:
new 内部类类名();--------->new Outer.Inner();
Static修饰:
如果在其他的类中想要调用静态内部类中的静态方法,我们可以先找到静态内部类的类名,然后根据类名
其他类中来调用静态内部类中的静态函数和变量,操作如下所示:Outer.Inner.method();
外部类中调用静态内部类中的静态函数和变量,Inner.method();
注意:此时的内部类函数和变量要用static修饰
Private修饰:
当一个类中的成员被私有了,只能在这个类中访问。
注意:被私有的成员内部类,只能在本类的其他方法中创建对象,然后外界去调用外部类的这个成员方法,通过这个成员方法在间接的让内部类中的方法运行。
2.局部内部类:
注意:局部内部类不能被成员修饰符修饰。
注意:局部内部类只能在局部内部类所在的函数中访问,出了函数无法访问。
内部类定义在局部时,只能访问被final修饰的局部变量。如果不被final修饰会报错误。
3.匿名内部类:
格式:
new 父类 或 接口(){
复写父类或实现接口中的函数
};
说明:
1)注意大括号后面有一个英文的分号,不能省略。
2)匿名内部类格式是固定的,以后在开发中遇到以上格式,要知道是匿名内部类格式即可。
3)匿名内部类只能创建在外部类的局部位置,且如果想通过匿名内部类调用其中的多个函数,可以将匿名内部类赋值给父类或者接口对象。再用对象名调用函数。
即:父类/接口 变量名= new 父类/接口(){
复写或者实现父类、接口中的函数
};
变量名.函数名1;
变量名.函数名2;
4.总结:
1、什么情况下使用匿名内部类?
如果我们定义一个类,实现了接口 或继承父类,仅仅只为复写父类或者实现接口中的方法, 这时我们专门定义的这个类有点多余,这时可以使用Java中提供的匿名内部类完成。
2、匿名内部类都是接口或者父类的实现类或子类对象。