一.类与对象
1.类和函数
面向对象的程序单位是类,而面向过程的程序单位是函数,因此面向对象比面向过程更简单,易用。
2.面向对象的基本特征
1> 封装
将对象的实现细节隐藏起来,然后通过一些公用方法来暴露该对象的功能;
2> 继承
面向对象实现软件复用的重要手段,当子类继承父类后,子类作为一种特殊的父类,将直接获得父类的属性和方法;
3> 多态
子类对象可以直接赋给父类变量,但运行时依然表现出子类的行为特征,这意味着同一个类型的对象在执行同一个方法时,可能表现出多种行为特征。
3.定义类
1> 定义成员变量
修饰符:修饰符可以省略,也可以是public,protected, private, static, final,其中public,protected,private三个最多只能出现其中之一,可以与static,final组合起来修饰成员变量。
2>定义方法语法格式
修饰符:修饰符可以省略,也可以是public, protected, private, static, final, abstract. 其中public, protected, private三个最多只能出现其中之一;abstract和final最多只能出现其中之一,他们可以与static组合起来修饰方法。
3> static
3.1.static主要是用于修饰方法,成员变量等成员,static修饰的成员表明它属于这个类本身,而不属于该类的单个实列。通常把static修饰的成员变量和方法也称为类变量,类方法。不使用static修饰的普通方法,成员变量则属于该类的单个示例,而不属于该类。因为通常把不使用static修饰的成员变量和方法也称为实例变量,实例方法。
有时也把static修饰的成员变量和成员方法称为静态变量和静态方法。静态成员不能直接访问非静态方法的。
3.2.static修饰的方法和成员变量,既可以通过类来调用,也可以通过实例来调用;没有使用static修饰的普通方法和成员变量,只可以通过实例来调用。
3.3 如果确实需要在静态方法中访问另一个普通方法,则只能重新创建一个对象。
public class StaticAccessNonStatic
{
public void info()
{
System.out.println("简单的info方法");
}
public static void main(String[] args)
{
// 因为main()方法是静态方法,而info()是非静态方法,
// 调用main()方法的是该类本身,而不是该类的实例,
// 因此省略的this无法指向有效的对象
//info();
//创建一个对象作为调用者来调用info方法
//new StaticAccessNonStatic().info();//方法一
//方法二:
StaticAccessNonStatic sa = new StaticAccessNonStatic();
sa.info();
}
}
4.方法详解
4.1 Java里的方法不能独立存在,所有的方法都必须定义在类里,方法在逻辑上要么属于类,要么属于对象。
同一个类的一个方法调用另外一个方法时,如果被调方法是普通方法,则默认使用this作为调用者;如果被调用方法时静态方法,则默认使用类作为调用者。也就是说,表面上看起来某些方法可以被独立执行,但实际上还是使用this或者类来作为调用者。
4.2 方法的参数传递机制
Java里方法的参数传递方式只有一种,值传递,所谓值传递,就是将实际参数值的副本(复制品)传入方法内,而参数本身不受到任何影响。
public class PrimitiveTransferTest
{
public static void swap(int a , int b)
{
// 下面三行代码实现a、b变量的值交换。
// 定义一个临时变量来保存a变量的值
int tmp = a;
// 把b的值赋给a
a = b;
// 把临时变量tmp的值赋给a
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
交换结束后,变量a的值是6;变量b的值是9
上面是基本类型的参数传递,Java对于引用类型的参数传递,一样采用的是值传递的方式。
class DataWrap
{
int a;
int b;
}
public class ReferenceTransferTest
{
public static void swap(DataWrap dw)
{
// 下面三行代码实现dw的a、b两个成员变量的值交换。
// 定义一个临时变量来保存dw对象的a成员变量的值
int tmp = dw.a;
// 把dw对象的b成员变量值赋给a成员变量
dw.a = dw.b;
// 把临时变量tmp的值赋给dw对象的b成员变量
dw.b = tmp;
System.out.println("swap方法里,a成员变量的值是"
+ dw.a + ";b成员变量的值是" + dw.b);
// 把dw直接赋为null,让它不再指向任何有效地址。
dw = null;
}
public static void main(String[] args)
{
DataWrap dw = new DataWrap();
dw.a = 6;
dw.b = 9;
swap(dw);
System.out.println("交换结束后,a成员变量的值是"
+ dw.a + ";b成员变量的值是" + dw.b);
}
}
结果
swap方法里,a成员变量的值是9;b成员变量的值是6
交换结束后,a成员变量的值是9;b成员变量的值是6
上述例子很容易给人造成一种错觉:调用swap()方法时,传入swap()方法的就是dw对象本身,而不是它的复制品。
创建一个对象时,系统内存中有两个东西:堆内存中保存了对象本身,栈内存中保存了引用该对象的引用变量。
根本点是main方法中的dw是一个引用(也就是一个指针),他保存了DataWrap对象的地址值,当把dw的值赋给swap方法的dw形参后,即让swap方法的dw形参也保存这个地址值。
所以为了更好地证明main方法中的dw和swap方法中的dw是两个变量,在swap方法的最后一行增加如下代码:
// 把dw直接赋为null,让它不再指向任何有效地址。
dw = null;
4.3 形参个数可变的方法
public class Varargs
{
public static void test1(String [] books)
{
for(String tmp:books){
System.out.println(tmp);
}
}
// 定义了形参个数可变的方法
public static void test(int a , String... books)
{
// books被当成数组处理
for (String tmp : books)
{
System.out.println(tmp);
}
// 输出整数变量a的值
System.out.println(a);
}
public static void main(String[] args)
{
// 调用test方法
test(5 , "九阴真经" , "葵花宝典");
test1(new String[]{"九阴真经","葵花宝典"});
}
}
二.成员变量和局部变量
定义一个成员变量时,成员变量将被放置到堆内存中,成员变量的作用域将扩大到类存在范围或者对象存在范围,这种范围的扩大有两个害处:
增大了变量的生存时间,这将导致更大的内存开销。
扩大了变量的作用域,这不利于提高程序的内聚性。
三.使用访问控制符
private: (当前类访问权限)如果类里的一个成员,使用private访问控制符来修饰,则这个成员只能在当前类的内部被访问。
default:(包访问权限) 如果类里的一个成员,或者一个外部类不使用任何访问控制符修饰,就称为包访问权限的。default访问控制的成员或外部类可以被相同包下的其他类访问。
protected(子类访问权限) 如果一个成员使用protected访问控制符修饰,那么这个成员既可以被同一个包中的其他类访问,也可以被不同包中的子类访问,通常情况下,如果使用protected来修饰一个方法,通常是希望其子类来重写这个方法。
public(公共访问权限) 如果一个成员或者一个外部类使用public访问控制符修饰,那么这个成员或外部类就可以被所有类访问,不管访问类和被访问类是否处于同一个包中,是否具有父子继承关系。
控制符使用的几个基本原则
1.1 类里的绝大部分成员变量都应该使用private修饰,只有一些static修饰的,类似全局变量的成员变量,才可能考虑使用public修饰。除此之外,有些方法只用于辅助实现该类的其他方法。这些方法被称为工具方法,工具方法也应该使用private修饰的。
1.2 如果某个类主要用做其他类的父类,该类里包含的大部分方法可能仅希望被其子类重写,而不想被外界直接调用,则应该使用protected修饰这些方法。
1.3 希望暴露出来给其他类自由调用的方法应该使用public修饰。因此,类的构造器通过使用public修饰,从而允许在其他地方创建该类的实例。因为外部类通常都希望被其他类自由使用,所以大部分外部类都使用public修饰的。
四.package, import和import static
1.java允许将一组功能相关的类放在同一个package下,从而组成逻辑上的类库单元。
2.java规定:位于包中的类,在文件系统中也必须有与包名层次相同的目录结构
Hello.java
package lee;
public class Hello
{
public static void main(String[] args)
{
System.out.println("Hello World!");
}
}
编译java文件时需要使用javac -d . Hello.java就可以在当前的目录下生成lee目录中的Hello.class
对于上面的Hello.class 必须放在lee文件夹下面才是有效的。
Apple.java
package lee.sub;
public class Apple
{
}
HelloTest.java
package lee;
import lee.sub.Apple;
public class HelloTest
{
public static void main(String[] args)
{
//直接访问相同包下的另一个类,无须使用包前缀
Hello h = new Hello();
// 使用类全名的写法
lee.sub.Apple a = new lee.sub.Apple();
// 如果使用import语句来导入Apple类后,就可以不再使用类全名
Apple aa = new Apple();
}
}
import static用于导入指定类的某个静态成员变量,方法或全部的静态成员变量,方法。