面向对象进阶
1.类变量
1.基本介绍:
a:类变量也叫静态变量/静态属性。(在类中的变量)
b:是该类的所有对象共享的变量(对象是在类中创建,只要是这个类创建的对象,自然都可以使用它)
任何一个该类对象去访问它时,取到的都是相同的值,任何一个该类的对象去修改它时,修改的也是同一个变量;
c:类变量随着类的加载就生成了,所以没有创建对象实例也可以访问;
2.演示:
ackage static0;
public class static1
{
public static void main(String[] args) {
System.out.println(A.name);
A a=new A();
System.out.println(a.name);//类变量的访问也要遵守访问权限
}
}
class A{
public static String name="kk";
//普通属性/普通成员变量/非静态属性/非静态成员变量/实例变量
public int age;
}
2.类方法:
1.基本介绍:
1.类方法使用场景:如果我们不希望创建实例(对象),也可以调用某个方法(即把类方法当作工具来使用)
eg:当创建一个类时:在类里面写方法,1.当调用普通方法时要new对象,
2.而调用静态方法,不需要创建对象,直接使用类.方法名调用
//2.经典应用场景:开发自己工具类时,可以将方法做成静态的,便于调用
//1.类方法(静态方法):
//被这个类的所有对象共享
//2.语法: 访问修饰符 static 数据类型 方法名(){};
//eg: public static double pay(){};
//当使用了static后就变成了静态方法,静态方法就可以访问静态变量·/属性
//3.访问:
//1.类名.类方法名()!!!!
//2.对象名.类方法名();
//注意:但也需要遵守访问权限
2.演示1:
package static0.method;
public class eg {
public static void main(String[] args) {
C student=new C("tom");//创建对象
C.payfee(100);//交100,理解为向C类内存空间中放200
C student1=new C("JACK");//创建对象
C.payfee(200);//交200:理解为向C类中内存空间放200
C.showfee();//使用类调用静态方法:理解为:C类内存空间中一共有多少钱
}
}
class C{
public static double fee;//静态属性
private String name;
//构造器:
public C(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public static void payfee(double fee){
C.fee+=fee;
}
public static void showfee(){
System.out.println(C.fee);
}
}
演示2:
package static0.method;
public class eg2 {
public static void main(String[] args) {
System.out.println(MyTools.calsum(5,6));//不需要new对象,直接调用!!!!
//eg:求和,余数................
}
}
class MyTools{
public static double calsum (double n1,double n2){
return n1+n2;
}
}
3.类方法细节:
a:类方法和普通方法都是随类的加载而加载,将结构信息存储在方法区;
所以可以直接使用类调用静态方法:(只有静态方法可以,普通方法不可以)
b:类方法中不能用this,普通方法可以;
c:类方法中不允许使用和对象有关的关键字eg:this,super;但普通方法可以;!!! (类加载时还没有对象)
d:静态方法(类方法)只能访问静态成员:(静态变量(类变量),或者静态方法) :!!!
但!!!普通成员既可以访问静态成员(类成员)也可访问非静态成员
e:非静态成员可以直接访问,静态成员必须按照规则访问(但都要遵守访问权限)
f:如果静态方法要访问本类的非静态成员,需要先再方法中创建对象,再调用!!!
//小结:静态方法只可以访问静态成员,非静态方法可以访问(该类的)全部成员,但都要遵守访问权限规则
4.main方法:
1.简介及演示
/mian方法:
//一:解释main方法形式:public static void main(String[]ages);
//1.public: main()方法是:java虚拟机调用,所以访问权限必须是public
//2.static:因为java虚拟机执行main方法时不必须要创建对象 eg:类.方法()
//3.String[]args:字符串数组,main方法形参的值是从哪里传进去的:
// 在执行这个程序时接受的命令会当作一个字符串数组传进去
//二:main方法特别说明:
//main方法:是static,所以只能访问该类静态成员(静态属性/方法),不能访问该类中的普通成员
//如果想要访问则必须在main方法中new对象来访问
package static0;
public class main1 {//类
private static String name = "kk";//静态变量/属性
private int age=100;//普通成员
public static void hi(){//静态方法:
System.out.println("hello");
}
public void info(){//非静态方法
System.out.println("jini");
}
public static void main(String[] args) {//main静态方法!!!!!!!
// :静态方法可以访问本类的静态成员(方法或属性)
System.out.println(name);
main1.hi();//访问静态方法
//System.out.println(age);静态方法main不能访问本类的非静态成员
//info();//静态方法mian不能访问本类的非静态成员
//f:如果静态方法要访问本类的非静态成员,需要先创建对象,再调用!!!
main1 m=new main1();//创建对象:在main方法中
System.out.println(m.age);
m.info();
}
}
5.静态属性和静态方法的经典使用:
1.简介:
设计模式是在大量的实践中总结和理论化之后的优选的代码结构,编程风格,以及解决问题的思考方式;
2.例子:
以单例模式举例
//单例(单个的实例(创建1个对象!))
1.[饿汉式]:
2.[懒汉式]:
3.【饿汉式】
//(1.)[饿汉式]:
//饿汉式单例模式实现步骤:
//1.将构造器私有化:(防止用户直接new对象)
//(私有化后就不能在外边new对象了,因为私有的只能在本类访问)
//2.类的内部创建静态对象
// (在类加载时对象就初始化好了,即使你不会使用它->饿汉式)
//3.向外暴露一个静态的公共方法返回对象
// (静态原因:因为我们想要在不new对象的前提下可以调用这个方法:使用类)
//4.代码实现
//5.弊端:对象,通常是重量级的对象,可能创建了对象,但不会使用
4.演示:
//希望在程序运行过程中只能有1个girlfriend:
public static void main(String[] args) {//main静态方法
//直接通过方法获得对象
GirlFriend g1=GirlFriend.getGirlFriend();//"="右边是调用方法,
// 它返回一个GirlFriend,所以“=”左边要创建一个GrilFriend类的变量;
System.out.println(g1);
System.out.println("----------------------------");
System.out.println(GirlFriend.age);
System.out.println("第二次调用");
GirlFriend g2=GirlFriend.getGirlFriend();
System.out.println(g2);
}
}
//希望在程序运行过程中只能有1个girlfriend
class GirlFriend{
private String name;
public static int age=100;
private GirlFriend(String name) {//1.构造器私有
System.out.println("构造器被调用");
this.name = name;
}
private static GirlFriend girlFriend=new GirlFriend("fjy");
//2.在类内部创造静态对象
public static GirlFriend getGirlFriend(){//3.向外提供一个静态的方法返回对象!!!
return girlFriend;
}
}
5.【懒汉式】
//希望在程序执行过程中只能有一个Cat对象:
package static0;
//懒汉式单例模式
public class Apply2 {
public static void main(String[] args) {
Cat cat1=Cat.getCat();//需要使用实例对象时调用方法-》:创建实例对象!!!!!!!!!!!
System.out.println(cat1);
System.out.println(Cat.age);//并不会调用构造器
//第二次调用!!!
Cat cat2=Cat.getCat();
//再次调用时,Cat对象不为空,所以就会把上次的cat对象返回-》:保证只会创建一个对象
//懒汉式:综上:只有当用户调用getCat方法时才会返回Cat对象,而当再次调用时,会返回上次创建的Cat对象
//从而保证了对象的单例
}
}
//希望在程序执行过程中只能有一个Cat对象
class Cat{
private String name;
public static int age=111;
private Cat(String name) {//1私有构造器
this.name = name;
}
private static Cat cat;//2.在类内部创造(普通对象)!!!
//对象如果没有初始化则默认为null!!!
//3.提供一个public 静态方法用于返回Cat对象!
public static Cat getCat(){
if(cat==null){//如果对象为空(没有初始化),就给他初始化
cat=new Cat("jini");//
}
return cat;//之后再返回
}
}
3.代码块
1.简介:
//1.代码块:又叫(初始代码块),在类中(是类的一部分),类似于(方法),将逻辑语句封装在方法体中,
// 通过{}包围起来
//2.基本语法:
//[修饰符]{
//};
//a:修饰符要么不写要么只可写static:分为:普通(非静态)代码块,静态代码块
//b:不通过对象或类显示调用,而是加载类或创建对象时隐式调用
//c:代码块中可以加入任何逻辑语句(...)
//1.代码块:相当于另外一种的构造器(对构造器进行补充),可以做初始化的操作!!!
//2.应用场景:如果多个构造器中都有重复的语句,可以抽取到(代码块)中,提高代码的复用性;
//4.当写了代码块后,不管调用哪个构造器创建对象,都会先调用代码块内容:即(代码块优先于方法)
//5.代码块的调用顺序优先于构造器;
2.演示:
public class CodeBlock1 {//类:
public static void main(String[] args) {
KK kk=new KK("kk",1000,"zhiyin");
}
}
class KK {//KK类:
//属性
private String name;
private double money;
private String actor;
//代码块:
//三个构造器都有这部分内容,可以抽出来放到代码块中
{
System.out.println("坤坤来了");
System.out.println("坤坤开始跳舞了");
System.out.println("几你太美");
}
//构造器:
//:三个构造器都有这部分内容,可以抽出来放到代码块中
public KK(String name) {//方法(构造器)重载!!!!!
/*System.out.println("坤坤来了");
System.out.println("坤坤开始跳舞了");
System.out.println("几你太美");*/
this.name = name;
}
public KK(String name, double money) {
/*System.out.println("坤坤来了");
System.out.println("坤坤开始跳舞了");
System.out.println("几你太美");*/
this.name = name;
this.money = money;
}
public KK(String name, double money, String actor) {
/*System.out.println("坤坤来了");
System.out.println("坤坤开始跳舞了");
System.out.println("几你太美");*/
this.name = name;
this.money = money;
this.actor = actor;
}
}
3.代码块细节:
1.细节1:
//代码块细节:!!!
//1.static代码块:即静态代码块,作用:!!!(对类进行初始化)!!!,!随着类的加载而执行!
// 无论创建多少个对象静态代码块只会执行一次!!(因为类加载也只有一次)
//而普通代码块(非静态),每创建一个对象,就会执行一次
package CodeBlock;
public class detail2 {
public static void main(String[] args) {
//Animal animal=new Animal();
M cat=new M();
//如过代码块是静态:只会执行一次(因为类信息只会加载一次)!!!!
//eg:
DD dd=new DD(); //只会执行一次代码块System.out.println("kk");
DD dd1=new DD();//因为类信息只会加载一次,而普通代码块:每创建一次对象就执行一次代码块
}
}
class Animal {//类
static {
System.out.println("Animal类的代码块被加载");
}
}
class M extends Animal {//子类
static {
System.out.println("Cat类的代码块被加载");
}
}
class DD{
static {
System.out.println("kk");
}
}
2.细节2:
//2.类什么时候被加载:!!!!!!!!!!
//a:创建对象实例时(new)
//b:创建子类对象实例时,父类会被加载(且父类先加载,子类后加载):先访问父类再访问子类
//c:使用静态成员时(静态属性,静态方法)
//即在类中如果有代码块,会先调用代码块,然后再访问其它的内容!!!
package CodeBlock;
public class details03 {
public static void main(String[] args) {//main静态方法
System.out.println(JN.name);//只要有类就会加载类的信息:
// 所以会先输出静态代码块(初始化类),现在并不会执行普通代码块:因为普通代码块的执行需要new对象;
//也可以理解为构造器没有被调用,因为普通代码块是构造器的补充!!!!!!!!!!
//所以:会先执行静态代码块L”姬你太没“,再执行静态属性:”kk“
JN jn=new JN();//访问非静态属性;
System.out.println(jn.age);//也会先访问代码块,再执行其它内容
}
}
class JN{//类
public static String name="kk";//静态属性
public int age=100;
static {//静态代码块
System.out.println("姬你太没");
}
{//普通代码块
System.out.println("你干嘛啊啊啊");
}
}
3.总结:
/3.总结:a:静态代码块(可以理解为方法)和类加载有关,与对象无关,只会加载1次所以无论new多少对象,都只执行1次!!!!!!!!!!!
// b:而普通代码块与类加载无关,只和对象有关,所以只有new对象时才会执行普通代码块,且每new一个就执行一次普通代码块
//c:但是都会优先访问代码块(因为初始化类),再访问其它;
4.final:
1.基本介绍:
/一:基本介绍:
/*final关键字:(最后的,最终的)意思,不可修改!!!!
1.final可以修饰类,属性,方法,局部变量;
2.final应用的背景(需求):
a:当不希望类被继承时,可以使用final修饰类
b:当不希望父类的方法被子类覆盖(重写)(override),使用final修饰;
c:当不希望类的某个属性的值被修改,可以使用final修饰;eg:
d:当不希望某个局部变量被修改,可以使用final修饰
2.演示:
package Final;
public class final1 {
public static void main(String[] args) {
F f=new F();
System.out.println(f.age);
//可以修改age的值3.
//f.age=200;:当age变量加上final时就不可以改变!!!
System.out.println(f.age);
//当不希望age变量的值可以修改时,在age前加上fianl;
}
}
final class A{
}
//class B extends A{}
class D{
final public void info(){
System.out.println("jinitaimei");
}
}
class E extends D{
/*public void info(){//因为父类D的方法info前面有fianl,所以不可以修改
System.out.println("kk");
}*/
}
class F{
final public int age=100;
public void info2(){
final int n1=10;
//n1=20;d:当不希望某个局部变量被修改,可以使 final修饰
}
}
3.细节1:
details:
1.final修饰的属性叫常量,一般用XX_XX_XX来命名;
2.final修饰的属性在定义时,必须赋初值,并且以后【不能再修改】
赋值可以在如下位置之一:
如果fianl修饰的是普通常量
(1.)定义时,如public double Tax_RATE=0.08;(推荐!!!!!!)
(2.)在构造器中
(3.)在代码块中
3.但如果final修饰的是静态的属性,则初始化的位置只能是
(1.)定义时
(2.)在静态代码块中
(3.)不能在构造器中:因为静态会在类加载时就执行,而构造器只有当new对象时才会使用,
那时已经定义了属性但未完成赋值,不符合常量必须同时定义和赋值规则
4.演示
package Final;
public class final2 {
public static void main(String[] args) {
}
}
class AA{
public double Tax_RATE=0.08;//定义时赋值;
public double Tax_RATE0;//定义时赋值;
public double Tax_RATE1;//在代码块赋值
public AA() {//在构造器中赋值;
Tax_RATE = 0.02;
}
{//(代码块本质是构造器的补充机制)
Tax_RATE1=0.04;
}
}
5.细节2:
4.final类不能继承,但可以实例化对象
5.如果类不是final类,但是含有final方法,则该方法虽然不能重写,但可以被继承调用;
6.如果一个类已经是final,就没必要再将方法修饰成final方法
7.fianl不能修饰构造器
8.!!!fianl和static往往搭配使用,不会导致加载类,底层编译器做了优化处理//eg在FinalDetails中!!
9.包装类(Integer,Double,Float,Boolean等都是final),String也是final,注意:所以不可以继承
6.练习:
分析下面代码是否正确:
package Final;
public class Finalexercise {
public int add(final int x){
x++
return x+1;
}
}
*/
/*
找出上述代码问题:
final:代表不可修改,final修饰x:表示x不可修改
而++x:意在修改x的值,所以错误!!!
而return x+1:正确:因为最终是返回x再加1,并没有改变x值;
*/
5.抽象类:
1.基本介绍:
一:抽象类的基本介绍:
1.当父类的某些方法,需要声明,但是有不确定如何实现时,可以将其声明为抽象方法(没有方法体),那么这个类就是抽象类
(比如:父类写了某个方法,子类还要重写)
2.总结:当父类的方法不确定时,可以使用abstract关键字修饰该方法,这就是抽象方法,用abstra修饰的类叫抽象类
(方法设为抽象后类也必须设为抽象)
3.抽象方法:是没有实现的方法,
4.抽象方法没有方法体!!!
2.演示:
package Abstract;
public class abstract0 {
public static void main(String[] args) {
}
}
abstract class Animal {
private String name;
abstract public void eat();
package Abstract;}
3.细节:
/*抽象类细节1:在设计模式用的多!!!
1).抽象类不能被实例初始化(不能new);
2.)抽象类中不一定要有抽象方法,也可以有可实现方法(非抽象方法)
3.)如果有抽象方法,则类必须为抽象类,但如果没有抽象方法,则类可抽象也可不抽象!!!!
4.)abstract(抽象)只能修饰方法和类!!!!不可修饰属性和其它;
5.)因为父类时抽象方法,所以方法的实现需要子类来实现(相当于方法重写)!!!!
抽象了细节2:
1.)抽象类的本质还是类,所以可以有类的所有成员
2.)抽象类不能有主体;:即抽象类不能创建(有)实例对象:因为没有具体的实现方法
3.)如果一个类继承了抽象类(抽象类本质还是类,所以可以被继承),
则它必须!实现!抽象类的所有的抽象方法,除非它自己也声明为abstract类。
//所谓实现方法:就是有{}(方法体),即使里面什么都没有;
4.)!!!!抽象方法不能使用final,static,private修饰,因为这些关键字都是和重写相违背的(与重写无关)
a:final:因为需要子类来实现父类的抽象方法!,fianl代表不可修改;
b:private:因为需要子类来实现父类的抽象方法,private只可在本类访问
c:static:修饰静态方法,可以被类调用实现功能,而abstract(抽象)方法要求没有方法体,这两个相违背;
4.演示:
public class abstractDetails1 {
public static void main(String[] args) {
}
}
abstract class AA{//抽象类
abstract public void info();//抽象方法:也可没有// ;
abstract public void info3();
public void info1(){//可实现方法
System.out.println("姬你太没");
}
}
abstract class MM extends AA{//继承抽象类,则需要继承所有的抽象方法/或者改为抽象类
public void info(){
}
public void info3(){};
}