注意:1 static修饰的成员变量不能访问没有static修饰的成员。static修饰的成员表明它属于这个类本身,而不属于该类的单个实例。通常把static修饰的成员变量和方法称为类变量,类方法。不使用的称为实例变量,实例方法。
2 java语言通过new关键字来调用构造器,从而返回该类的实例。
3 构造器没有返回值,也不能用void声明。因为构造器的返回值是隐式的,实例化的时候会把类的实例当成返回值。、
4 实例化类:Person p =new Person();
类是一种引用数据类型,如同Person p=new Person()一样,一种p存储在栈中,而真正的实例存储在堆内存中,
p指向堆中的实例。如果希望垃圾回收机制回收某个对象,只需切断该对象的所有引用变量和它之间的关联即可。
this关键字最大的作用就是让类中的一个方法,访问该类的另一个方法或实例变量。而不用去重新创建对象,节省了内存。
注意:static修饰的方法中不能使用this关键字,所以static修饰的方法不能访问不使用static修饰的普通成员,也就是静态成员不能直接访问非静态成员。java编译时不要使用对象去调用static修饰的成员变量、方法,而应该使用类去调用static修饰的成员变量、方法。
使用static修饰的方法既可以使用类作为调用者来调用,也可以使用对象座位调用者来调用。同样没有static修饰的方法不能使用类作为调用者来使用。
消息传输机制:
public class PrimitiveTransferTest
{
//用于交换两个数
public static void swap(int a,int b)
{
int temp=a;
a=b;
b=tmp;
System.out.println("swap的方法里,a的数值是"+a+";b的数值是"+b);
}
public static void main(String[] args)
{
int a=6;
int b=9;
swap(a,b);
System.out.println("交换结束后,a的数值是"+a+";b的数值是"+b);
}
}
此程序的运行结果是 swap的方法里,a的数值是9;b的数值是6
swap的方法里,a的数值是6;b的数值是9
其中在内存中系统为main方法和swap方法分配两块栈区,产生了两个a变量和两个b变量。只是存在于不同的方法区而已。
前面的是基本类型的传递,还有引用传递,引用传递传递的是地址的值,实际都是指向堆中的对象。所以不管是main方法还是swap都会发生改变。
方法:在形参的类型后增加三点(…),则表明该形参可以接受多个参数值,多个参数值被当成数组传入。
需要注意的是个数可变的形参只能存在于形参列表最后。
public calss Varargs
{
public static void test(int a String... books)
{
//把books当成数组来处理
for(String tmp:books)
{
System.out.println(tmp);
}
System.out.println(a);
}
public static void main(String[] args)
{
test(5,"码农翻身","成功学");
}
}
注意:java允许一个类中定义多个同名方法,形参不同就行。
概念:变量分为成员变量和局部变量,在成员变量中有static修饰的变量为类变量,没有的是实例变量,类变量跟随类一直存在。
注意:成员变量和局部变量成员名相同时,局部变量会覆盖成员变量。但是可以使用this或者类名.来调用成员变量。尽量避免通过实例对象访问类变量
注意:尽可能缩小局部变量作用域范围,这样它在内存中的停留时间就越短,能用代码块最好。同时成员变量也是十分消耗内存的。
java程序推荐将类和对象的成员变量进行封装。目的是对数据进行保密,让使用者只能通过事先预定的方法来访问数据。例如Person类中的age等成员变量。
优先级从低到高分别是 private,default,protected,public。
注意:如果一个java源文件里定义了一个public修饰的类,则这个源文件的文件名必须与public修饰的类的类名相同。
java类中的setter和getter方法有着重要的意义,如果一个类中的所有实例变量都用private修饰并且有sette和getter方法,那么就是一个符合javabean规范的类。
public class Person
{
private String name;
private int age;
//提供方法来操作name成员变量
public void setName(String name)
{
//执行校验
if(name.length<2||name.length>6)
{
System.out.println("设置的任命不符合要求");
return;
}
else
{
this.name=name;
}
public String getName()
{
return this.name;
}
public void setAge(int age)
{
if(age>100||age<0)
{
System.out.println("设置的年龄不符合要求");
return;
}
else
{
this.age=age;
}
}
public int getAge()
{
return this.age;
}
}
}
public class PersonTest
{
public static void main(String[] args)
{
Person p=new Person();
//程序会报错,因为age已经被隐藏无法直接访问
p.age=1000;
//这个程序是正确操作
p.setAge(30);
System.out.println(p.getAge());
p.setName("李刚");
System.out.println(p.getname());
}
}
注意以下规则
1 类中绝大部分成员变量都应该用private修饰,只有一些static除外
2 如果一个类主要用作其他类的父类,并且只希望被自己子类重写,那么用protected。
在java中import不是必须的,只要在类中坚持使用其他类的全名也可以。java默认所有的源文件倒入在java.lang包下的所有类中。
注意:在有些情况下会要求使用全名(例如类名相同难以区分的情况下)
构造器用于创建实例时执行初始化。
一个类中有多个构造器(形参列表不同),被称为构造器重载。
构造器重载时,可以使用this调用另一个重载的构造器。(只能在构造器中使用)
例如:
public class Apple
{
public String name;
public String color;
public double weight;
//无参构造器
public Apple(){
};
//两个参数的构造器
public Apple(String name,String color)
{
this.name=name;
this.color=color;
}
public Apple(String name,String color,double weight)
{
//通过this调用另一个构造器的初始化代码
this(name,color);
this.weight=weight;
}
}
注意:1 方法重写要遵循“两同两小一大”规则,两同即方法名相同、形参列表相同。两小指的是子类方法的返回值类型应该比父类的更小或者相等,子类方法声明抛出异常类应该比父类的更小或者相等。一大指的是子类方法的访问权限比父类的更大或者相等。
2 还要注意覆盖方法和被覆盖方法要么都是类方法(加static的方法),要么都是实例方法(没加static的方法),不能混。
3 使用private修饰符的方法不能被重写,子类也无法访问。
4 如果在子类方法中需要调用被覆盖了的父类的实例方法,可以使用super,例如super.fly(),就是调用了父类的fly方法。
public Baseclass
{
public int a=5;
}
public class Subclass extends BaseClass
{
public int a=7;
public void accessOwner()
{
System.out.println(a);
}
public void accessBase()
[
System.out.println(super.a);
}
public static void main(String[] args)
{
Subclass sc=new Subclass();
sc.sccessOwner(); //输出7
sc.accessBase(); //输出5
}
}
6 子类不会获得父类的构造器。但是可以调用父类构造器的初始化代码
7 子类构造器调用父类构造器使用super调用来完成,使用方法和this一样(可参考上面代码)
BaseClass Bc=new SubClass(); //其中SubClass是BaseClass的子类
程序在运行时,编译类型是BaseClass,运行类型是SubClass
当运行调用引用类型变量方法时Bc.test()(方法被子类覆盖),则表现出子类方法的行为特征。
条件:1 引用类型之间的转换只能在具有继承关系的两个类型之间进行。要把一个父类实例转换成子类类型的时候,对象必须
是子类实例才可以,就像这样BaseClass Bc=new SubClass(); 把子类转换成父类则不需要强制类型转换。
注意:为了保证程序的健壮性,可以使用instanceof来判断是否可以进行成功转换。
if(objPro instanceof String)
{
String str=(String)objPri;
}
介绍:instanceof运算符的前一个操作数通常是一个引用类型变量,后一个操作数通常是一个类(也可以是接口),
它用于判断前面的对象是否属于后面的类,或者是子类、实现类的实例。是的话但会true。
注意:继承会破坏封装,但是组合具有好的封装性。
继承使用规则:
1 尽量使用private修饰,避免子类篡改父类方法
2 尽量不要在父类构造器中调用将要被子类重写的方法。
继承的使用前提:
1 子类需要额外的属性添加,例如学生需要年级的属性,继承自Person,年级这个属性对学生又是必不可少的,此时可以派生子类。
2 子类需要添加自己的行为方式。
组合和继承一样同样是为了复用代码
组合是把旧类对象作为新类的成员变量组合进来。通常需要private修饰被组合的旧类对象
使用组合的场景:适合有复合关系,比如轮胎,车灯,组合成交通工具之类的。
class Tire {
public void run() {
System.out.println("轮胎转动...");
}
}
/**
* 车灯
*/
class Light {
public void light() {
System.out.println("灯亮...");
}
}
/**
* 交通工具
* 组合
*/
public class Vehicle {
private Tire tire;
private Light light;
public Vehicle(Tire tire,Light light) {
this.tire = tire;
this.light = light;
}
public void operation() {
light.light();
tire.run();
}
public static void main(String[] args) {
Tire tire = new Tire();
Light light = new Light();
Vehicle vehicle = new Vehicle(tire,light);
vehicle.operation();
}
}
//灯亮…
//轮胎转动…
组合和继承的关系:
继承与组合都是面向对象中代码复用的方式。父类的内部细节对子类可见,其代码属于白盒式的复用,而组合中,对象之间的内部细节不可见,其代码属于黑盒式复用。继承在编码过程中就要指定具体的父类,其关系在编译期就确定,而组合的关系一般在运行时确定。继承强调的是is-a的关系,而组合强调的是has-a的关系。
和构造器一样用于初始化java对象。执行在构造器之前。不能接受任何参数。
用法:如果有一段初始化代码对所有对象完全相同,且无需接收任何参数,就可以把这段初始化处理代码提取到初始化块中。(即可以将构造器中的无需参数且公共部分放入到初始化块中)
使用static修饰的初始化块是静态初始化块,也被成为类初始化块。静态初始化快在类初始化阶段就执行,因此比普通初始化块先执行。
注意:存在继承关系时,先初始化顶层父类静态初始化代码块。然后是直接父类静态初始化块。
class Root
{
static{
System.out.println("Root的静态初始化块");
}
{
System.out.println("Root的普通初始化块");
}
Root()
{
System.out.println("Root的无参构造函数");
}
}