<5>类
1)类和对象
类是把一类事物的静态属性和动态操作组合在一起所得的概念,相当于模型,或者说一个设计图纸。
对象是类的一个个体,是根据类这个设计图纸造出来的实物,会产生和消亡。
用汽车来做个比喻,类就是设计图,对象就是一辆辆生产出来的车。
class Person
{
int age;//age是类的属性,也叫类数据成员,字段,域
void shout()//shout是方法,也叫类的成员函数
{System.out.println(“oh!I am”+age)//shout方法可以直接访问同一个类中的age变量}
}
2)类的构造函数
class A
{
private int i; private int j;
public A()//构造函数的要求:无返回值,名字和自己所属的类相同。
{System.out.printf(“构造函数被调用了”)}
}
class Test
{
public static void main(String[] args)
{
A aa=new A();
}
}
输出结果为:构造函数被调用了。由此可见,构造函数在构造对象的时候会被调用自动执行。
构造函数可以带参,比如public A(int a, int b)
{i=a; j=b;}
创建对象变成A aa=new A(1,2)。则是在创建A对象的同时,给其属性i,j赋了值。
构造函数可以有多个,比如:public A(int a, int b)//第一个
{i=a; j=b;}
public A();//第二个
A aa=A(1,2);会使用第一个构造函数。A aa=A();会使用第二个构造函数。
类中默认会有一个无参的构造函数A()
所以就算在类中不定义A()的构造函数,A aa=new A();也是对的。但是如果你定义了A(),
那java就不会生成这个默认的无参构造函数A()。
3)用个例子说明“按钮”思想
class Triangle
{ int a ;int b; int c;
void set(int i, int j, int k)
{a=i; b=j; c=k}
}
class test
{public static void main(string[] args)
{
Triangle t=new();
t.a=1; t.b=2; t.c=3;//第一种赋值方法
t.set(1,2,3);//第二种赋值方法
}
}
那么第一种和第二种哪种方法好?第二种好
因为第二种方法,相当于对类Triangle的内部细节进行了封装操作,并不暴露给用户,只是给用户提供了一些简单的接口,就像这里的set一样。用户不需要知道a,b,c,用户只需要知道在set里面输入1,2,3就能达到自己想要的效果。如果我不给你提供set接口,用户就永远不能对类的内部细节abc进行操作,提高了安全性。
3)访问控制符
public,protect,default(默认),private。
在一个类的内部,所有的成员都可以相互访问,访问控制符是透明的,访问控制符是针对外部访问而言的。不可以通过外部访问方式访问类内部的private成员,其他都可。
外部访问的两种方式:通过类名访问类内部成员、通过类对象名访问类内部成员
4)函数的局部变量和类中的属性初始化
是否会自动初始化:
局部变量编译器不会自动进行初始化,属性会被自动进行初始化。函数中的局部变量如果不进行初始化,编译会出错。类中的属性如果不进行初始化,编译不会出错。
属性的自动初始化规则:
byte,short int,long int,int,float,double会被自动初始化为0
char会被自动初始化为‘\u0000’,表示空
boolean会被初始化为false
All reference(引用) type,相当于c中的指针类型,会被初始化为NULL
注意一旦编程者为类定义了初始化方法,系统就不再提供默认的初始化方法了
<6>函数的重载
同名的函数通过不同形参做相同的事情,这就是函数的重载。形参个数,形参顺序,形参数据类型必须至少有一个不同。举个例子:
C语言中,要实现相加操作
int add1(int a,int b);
double add2(int a,double b);
int add3(int a,int b,int c);
由于形参的不同,要构造的相加的函数名也不同
但是java中,只要是相加,都可以同名。
int add(int a,int b);
double add(int a,double b);
int add(int a,int b,int c);
虽然形参不同,但是相加的函数名相同。在调用函数时,要使用哪个函数,根据你传入的实参个数,实参类型,实参顺序来决定,你调用的是哪一个add函数。
注意,如果函数只是函数的返回值不同,而形参均相同,则不构成函数的重载,编译会报错。
<7>this
1)一个对象只含有属性的空间,多个对象共用一份方法的拷贝
class A
{
private int i;
public A(int j)
{i=j; }
public void show()
{
System.out.printf(“i=%d\n”,i)
}
}
class Test
{
public static void main(String[] args)
{
A aa1=new A(10);
A aa2=new A(20);
aa1.show();
aa1.show();
}
}
aa1,aa2存在栈里,A(10),A(20)存在堆里。aa1指向A(10),aa2指向A(20)。show函数存放在代码区。虽然aa1,aa2在内存中分别有自己的静态属性,但是动态可执行方法show方法只有只有一个,那么如何知道,show方法是被aa1还是aa2调用的呢?
实际上上面show函数,按照c语言写是这样
public void show(A *this)
{
System.out.printf(“i=%d\n”,(*this).i);
}
aa1.show()→aa1.show(aa1) aa2.show()→aa2.show(aa2)
也就是说,按照c语言的理解,在调用show函数的时候,会传入对象地址,以此来判定是哪个对象在调用show函数。使用show函数的时候,会根据对象地址,来获取对应的对象属性来进行输出。
按照java的理解,this就是一个隐含的指针,在非静态成员函数的形参列表中。当前时刻,哪个对象调用该函数,就会把调用该函数的对象的地址赋给this指针,这样,在函数内部可以通过this访问在调用该函数的对象的成员。
2)this使用实例:
class A
{
public int i=99;
public A(int i)
{
System.out.printf(“i=%d\n”,i); //在该方法里新定义了i,那么i就是这个新定义的i
}
public void show()
{
System.out.printf(“i=%d\n”,i);// 在该方法里没有新定义i,那么i就是类A的属性i
}
}
public class Test
{
public static void main(String[] args)
{
A aa1=new A(10);
aa1.show();
}
}
//输出结果为10,99
class A
{
public int i=99;
public A(int i)
{
this.i=i;//this代表当前时刻正在创建的对象
System.out.printf(“i=%d\n”,i);
}
public void show()
{
System.out.printf(“i=%d\n”,this.i)//this代表正在调用show函数的对象
}
}
class Test
{
public static void main(String[] args)
{
A aa1=new A(10);
aa1.show();
}
}
//输出结果为10,10
<8>static
1)static的几个性质
一个属性前如果增加了static,那么这个属性就不只是针对某一个对象,而是所有的这个类的对象公用这个属性。或者说,这个属性属于类,不属于某一个对象。示例:
class A
{
public static int a=10;
public void show()
{
System.out.printf(“i=%d\n”, a)
}
}
class Test
{
public static void main(String[] args)
{
A aa1=new();
A aa2=new();
aa1.a=20;
aa2.show();
}
}
//输出结果为20
static属性属于类本身,没有对象,仍然可以直接通过类名的方式访问该类内部的static属性。示例:
class A
{
public static int a=10;
}
class Test
{
public static void main(String[] args)
{
System.out.printf(“i=%d\n”, A.a)
}
}
//输出结果为10
static属性和方法虽然属于类本身,但是类对象也是这个类,所以可以通过类对象名的方式访问。示例:
class A
{
public static int a=10;
public static void show()
{
System.out.printf(“你好!”);
}
}
class Test
{
public static void main(String[] args)
{
A aa1=new();
aa1.show();
System.out.printf(“%d\n”,aa1.a);
}
}
//输出结果为:你好!10
static只表明了该成员可以通过类名访问的潜在特征,这个特征能不能表现出来,还需要满足一个条件,这个成员是非private的。
class A
{
private static int a=10;//private的static成员不能通过类名访问
private static void show()
{
System.out.printf(“你好!”);
}
}
class Test
{
public static void main(String[] args)
{
A.show();
A.a=20;
}
}
//报错
静态方法可以通过类名调用和对象名调用,非静态方法只能通过对象名调用。所以,有静态方法调用的权限不一定有非静态方法调用的权限(比如只有类,没有类对象),有非静态方法调用的权限,一定也会有静态方法调用的权限。以此可得,静态方法不能访问非静态成员,非静态方法可以访问静态成员。
换个方式理解:静态的是共有的,大家都有,调用时候知道是哪个。非静态的话,不同的对象有不同的,调用时候不知道调用的是哪个对象的非静态成员。
class A
{
public static void f()
{
g();//error!说明静态方法不可以访问非静态成员
}
public void g()
{
f();//ok!说明非静态方法可以访问静态成员
}
}
一个类的属性可以是个类对象,或者说一个事物可以包含另一个事物,比如汽车包含发动机
class A
{
public int i;
}
class B
{
public A aa=new A();
}
//aa是个对象,但是同时,也是B的属性
2)static的运用
统计造出了几个对象
class A
{
private int i;
public static int cnt=0;
public A()
{
++cnt;
}
public A(int i)
{
this.i=i;
++cnt;
}
public static int getcnt()
{
return cnt;
}
class Test
{
public static void main(String[] args)
{
System.out.printf(“当前的A对象的个数是:%d\n”,A.getcnt());
A aa1=new A();
System.out.printf(“当前的A对象的个数是:%d\n”,A.getcnt());
A aa2=new A(2);
System.out.printf(“当前的A对象的个数是:%d\n”,A.getcnt());
}
}
//输出结果为:0,1,2
保证A类型只造出一个对象
class A
{
public int i=20;
private static A aa=new A(); //aa的静态不能省, get方法静态不能访问非静态成员
private A()//static不用于构造方法,因为构造方法一定属于类本身,不需再加限定
{}
public static A getA()//静态不能省,因为外部无法创造出类对象,只能通过类名访问getA来创造对象
{
return aa;
}
}
class Test
{
public static void main(String[] args)
{
A aa1=A.getA();
A aa2=A.getA();
aa1.i=99
System.out.printf(“%d\n”,aa2.i);
If(aa1==aa2)
System.out.printf(“aa1和aa2相等\n);
else
System.out.printf(“aa1和aa2不相等\n);
}
}
//构造方法是私有,在外部不能直接创建A对象,只能在内部方法提供一个getA接口来返回A对象aa,无论调用多少次getA,都是一个类对象。
为什么private static A aa=new A();不会形成新对象和新aa的反复形成?个人理解,不知道是对是错。因为aa是static类型的,处在共享数据区。因为它属于类,不需要依附于对象存在。所以在没有形成对象的时候,就已经执行了这句代码,创建出了aa。而创建aa的同时也需要创建一个对象A。创建对象A的时候,会生成对象的静态属性i。但是由于static aa是属于类的,对象创建的时候,并不会再次创建aa,只生成了对象的静态属性i。所以最终的结果是,生成了一个指针aa,和aa指向的对象A,对象A中只包含静态属性i。同时对象A可以调用static aa,所以称aa也为对象A的属性。
<9>继承
1) 什么是继承
一个新类从已有的类那里,获得其已有的属性和方法。新类也叫子类、派生类。
旧类也叫父类、基类。还有一个说法叫超类,是所有类的老祖宗。
2) 继承有什么用
代码重用,形成一种类的层次体系结构,为多态创造条件。举个例子:
class Human
{
public String name=”张三”;
public int age=22;
}
Class Student extends Human
{
public double score=66.6;
}
//此时,类Student既有name,age属性,又有score属性。
3)单继承和多继承
单继承是说一个类继承一个父类,多继承是说一个子类继承多个父类。Java只支持单继承。
4)同包继承权限问题
和访问控制符有关,public、protected成员可以被继承,private成员不能被继承。private成员实际物理上已经被继承了过来,但是逻辑上不允许访问。
5)super
类的构造方法不会被继承,如果想要调用父类的构造方法,可以使用super;
一个构造函数里只能有一个super,如果有super必须放在构造函数的第一个语句位置;
如果不定义super,则构造函数里默认有一个super(无参),如果此时父类没有无参的构造函数,就会出错;
super的形参列表要和父类的构造函数形参列表有一个相同
举个例子:
class A
{
public int i;
public int j;
public A(int i,int j)
{
this.i=i;
this.j=j;
};
publie A(int i)
{
this.i=i;
};
}
class B extends A
{
public int k;
public B(int i,int j,int k;)
{
super(i,j);//ok!用super调用A的有参的构造函数,可以避免对继承来的i,j属性手动初始化
super();//error,父类没有无参构造函数引用
A(i,j)//error,因为构造方法没有继承
this.k=k;
}
}
6)子类访问父类成员的方式
子类的类对象名、子类内部直接访问继承来的,子类类名访问父类static
我个人不喜欢郝斌这个说法,我理解为继承来的就是自己的。所以不叫访问父类成员,应该叫访问从父类继承来的自己的成员。
<10>重写
对于父类中的方法体不满意,在子类中重新定义父类已有的方法;
重写方法必须和被重写方法的方法名称,参数列表和返回值类型相同;
重写方法的访问控制符比被重写方法的要更大
举个例子:
class A
{
public void f()//被重写方法
{
System.out.printf(“哈哈”);
}
public void f(int i)
{
System.out.printf(“嘿嘿”);
}
}
class B extends A
{
public void f()//重写方法
{
super.f();
f(10);//调用继承来的f(int i)
System.out.printf(“你好”);
}
}
public class test
{
public static void main(String[] args)
{
B bb=new B();
bb.f();
}
}
//输出结果是:哈哈嘿嘿你好
<11>多态
1) 什么是多态
一个父类引用,既可以指向父类对象,也可以指向子类对象,可以根据当前指向对象的不同,来调用不同对象里面的方法和成员;
2)多态使用的注意事项
class A
{
public void f()
{
System.out.printf(“AAAA”);
}
}
class B extends A
{
public void f()
{
System.out.printf(“BBBB”);
}
public void g()
{
System.out.printf(“BBBB”);
}
}
public class test
{
public static void main(String[] args)
{
A aa=new A();
aa.f();
B bb=new B();
bb.f();
//B cc=(B)aa;error
aa=bb;//ok
aa.f();
//aa.g(),error
B cc=(B)aa
cc.g();
//bb=aa,error
}
}
//输出结果为AAAA,BBBB,BBBB。
同样是aa,f(),为什么输出结果不一样呢?因为aa可以根据它自己当前时刻指向的是A类对象还是A子类对象,而自动决定调用的是哪个对象的f方法。
为什么aa=bb是对的,bb=aa是错的呢?因为父类引用可以指向子类对象,但是子类引用不能指向父类对象。怎么理解呢?父类是动物,子类是狗。动物包括狗,但是狗不能概括动物。
为什么aa=bb之后,可以使用f(),不能使用g()呢?因为父类引用指向子类对象之后,只可以调用从父类继承来的成员,不能使用子类自己本身独有的成员。
什么时候可以使用子类本身独有的成员呢?为什么B cc=(B)aa强制转化之前aa.g()出错,B cc=(B)aa强制转化之后,cc.g()可以呢?郝斌的说法是把父类转化为子类之后,子类的特有方法就可以进行调用。我个人理解还是和强制转化没关系,能否使用子类特有的成员,和存储这个子类对象的引用类型相关。
为什么在aa=bb之前,B cc=(B)aa的强制转化出错,之后,B cc=(B)aa的强制转化允许呢?因为只有在父类引用指向子类对象的时候,才能把父类引用的内容转化为子类引用的内容。
3)多态实例:
class A
{
public void f()
{
System.out.printf(“AAAA”\n);
}
}
class B extends A
{
public void f()
{
System.out.printf(“BBBB”\n);
}
}
class C extends B
{
public void f()
{
System.out.printf(“CCCC”\n);
}
}
public class Test
{
public void g(A aa)
{
aa.f();
}
public static void main(String[] args)
{
A aa=new A();
B bb=new B();
C cc=new C();
g(aa);
g(bb);
g(cc);
}
}
//输出结果为AAAA,BBBB,CCCC。也就是说,我在g函数只创建了一个A引用,凭借它指向的不同,就使用了它的子类BC里的函数f()。
标签:aa,java,--,void,多态,class,int,static,public From: https://www.cnblogs.com/fjcz/p/16983869.html