目录
- 类
- 对象
- 构造方法
- 引用与对象实例
- static
- final
- 封装
- 继承
- 方法重载与重写
- 多态
- 抽象类
- 接口
- 内部类
Java是面向对象的高级语言,类和对象是Java程序的核心。
类和对象
当我们买一部手机时,需要的是内存大一点、运行速度快一点、像素高一点等等,它是对象么?
不是,它是一个类。
当我们买了一部华为时,它就是一个对象。对象是具体的、确定的物体。
这部手机的颜色、尺寸、编号等是它的属性;我们使用手机来打电话、发短信的行为是它的“方法”。
-
创建类
类,是具有相同属性和方法的对象的集合。public class 类名{ // 属性(成员变量) 属性类型1 属性命1; ... // 方法 方法1; ...
一个类可以包含以下类型变量:
局部变量:在方法、构造方法或者语句块中定义的变量被称为局部变量。变量声明和初始化都是在方法中,方法结束后,变量就会自动销毁。
成员变量:成员变量是定义在类中,方法体之外的变量。这种变量在创建对象的时候实例化。成员变量可以被类中方法、构造方法和特定类的语句块访问。
类变量:也叫静态变量,类变量也声明在类中,方法体之外,但必须声明为 static 类型。 -
创建对象
创建类时,不会开辟内存进行存储。当创建对象时,才开辟内存存储属性和方法。类名 对象名 = new 类名();
// Test.java public class Test{ // 属性(成员变量) double height; int age; int sex; // 性别,0为男;非0为女 // 方法 void laugh(){ System.out.println("我有笑"); } void printBaseMes(){ System.out.println("我的身高是:" + height); System.out.println("年龄:" + age); if (this.sex == 0){ System.out.println("男"); } else{ System.out.println("女"); } } } // NewObj.java public class NewObj{ public static void main(String[] args){ Test test = new Test(); test.height = 170; test.age = 20; test.sex = 0; test.printBaseMes(); } }
关于对象中各变量的作用域:
1.局部变量的作用域仅限于定义它的方法内。而成员变量的作用域在整个类内部都是可见的。
2.同时在相同的方法中,不能有同名的局部变量;在不同的方法中,可以有同名的局部变量。
3.成员变量和局部变量同名时,局部变量具有更高的优先级。
构造方法
-
每个类至少会生成一个构造方法
1.构造方法名称与类名相同,没有返回值。
2.如定义类时如未定义构造方法,系统自动生成无参构造方法;如定义,则不再自动生成。// Test1.java public class Test1{ double height; int age; public Test1(double h, int a){ height = h; age = a; } void print(){ System.out.println("我的身高:" + height); System.out.println("我的年龄:" + age); } }
// NewObj.java public class NewObj{ public static void main(String[] args){ Test1 t1 = new Test1(170, 22); t1.print(); } }
3.构造方法的重载:可以定义多个构造方法,使用时系统据给定的不同参数自动选择相应的构造方法。
// Test1.java public class Test1{ double height; int age; int sex; // 性别,0为男,非0为女 public Test1(double h, int a){ height = h; age = a; } public Test1(int s){ sex = s; } void print(){ System.out.println("我的身高:" + height); System.out.println("我的年龄:" + age); } void printSex(){ if (sex == 0){ System.out.println("男"); } else{ System.out.println("女"); } } }
// NewObj.java public class NewObj{ public static void main(String[] args){ Test1 t1 = new Test1(170, 22); t1.print(); Test1 t2 = new Test1(0); t2.printSex(); } }
引用与对象实例
当Java新建一个对象时,只是创建了一种引用,类似于c语言中的指针,指向内存中存储数据的地址。
static
- 静态成员(或类成员)
// Static.java public class Static{ public static String str = "shiyan"; public String str1 = "test"; public static void main(String[] args){ // 静态成员,不需要实例化可以直接通过类名访问 System.out.println(Static.str); // 非静态成员,必须实例化后才可访问 Static str2= new Static(); System.out.println(str2.str1); } }
- 静态方法
不需要实例化即可调用。
不能使用关键字this
,不能访问非静态成员和非静态方法。
final
final 修饰类,则该类不允许被继承,为最终类
final 修饰方法,则该方法不允许被覆盖(重写)
final 修饰属性,则该类的属性不会进行隐式的初始化(类的初始化属性必须有值)或在构造方法中赋值(但只能选其一)
final 修饰变量,则该变量的值只能赋一次值,即常量
public final static String Test = "test";
封装
隐藏对象的属性和实现细节,仅对外公开接口,并控制对象属性的读和修改的权限。
- 权限修饰符
访问修饰符 | 本类 | 同包 | 子类 | 其它 |
---|---|---|---|---|
private | 1 | |||
默认 | 1 | 1 | ||
protected | 1 | 1 | 1 | |
public | 1 | 1 | 1 | 1 |
- getter/setter
对外提供的每个属性读写的公共访问方法。并在getter/setter中加入判断语句,否定非法输入。
// Test1.java
public class Test1{
private double height;
public double getHeight(){
return height;
}
public void setHeight(double newHeight){
height = newHeight;
}
}
// NewObj.java
public class NewObj{
public static void main(String[] args){
Test1 t1 = new Test1();
t1.setHeight(177);
System.out.println(t1.getHeight());
}
}
- this
代表当前对象。
当成员变量与局部变量相同时,局部变量优先级更高。如需访问成员变量,使用this.属性
。方法亦同。
继承
解决代码复用的问题。
class 子类 extends 父类
子类拥有父类除
private
以外的所有属性和方法;
子类可以有自己的属性和方法;
子类可以重写父类的方法;
Java中的继承是单继承,一个类只有一个你类。
补:Java实现多继承的方法implements接口。
// Animal.java
public class Animal{
public int legNum;
public void bark(){
System.out.println("叫");
}
}
// Dog.java
public class Dog extends Animal{
}
// Test.java
public class Test{
public static void main(String[] args){
Dog dog = new Dog();
dog.legNum = 4;
dog.bark();
}
}
- super
在子类内部使用,代表父类对象。
1.父类属性:super.属性
2.父类方法:super.bark()
3.子类构造方法需要调用父类的构造方法时,在子类构造方法体最前面加上:super()
方法重载与重写
- 方法重载
一个类中可以定义多个同名的方法,但每个方法的参数类型或参数个数都不一样。
方法中的参数列表必须不同。比如:参数个数不同或者参数类型不同。
重载的方法中允许抛出不同的异常
可以有不同的返回值类型,但是参数列表必须不同
可以有不同的访问修饰符
public class Test{
void f(int i){
System.out.println(i);
}
void f(double d){
System.out.println(d);
}
void f(String s1, String s2){
System.out.println(s1 + s2);
}
void f(String s, int i){
System.out.println(s + ", " + i);
}
public static void main(String[] args){
Test t = new Test();
t.f(0);
t.f(1.0);
t.f("I", "love u");
t.f("I", 4);
}
}
- 方法重写
子类继承父类的方法后,可以方法进行重写。
// Animal.java
public class Animal{
void bark(){
System.out.println("叫");
}
}
// Dog.java
public class Dog extends Animal{
// 重写
void bark(){
System.out.println("汪");
}
}
// Test.java
public class Test{
public static void main(String[] args){
Animal ani = new Animal();
Dog dog = new Dog();
ani.bark();
dog.bark();
}
}
多态
又称动态绑定。
同一消息,发送给不同的对象,产生不同的行为。
- 向上转型
子类可以自动向上转型为父类。反之,不行。
public class Test{
public static void main(String[] args){
// Dog -> Animal
// 遗忘子类中与父类不同的方法,重写与父类相同的方法
Animal ad = new Dog();
ad.bark();
}
}
- 多态的实现条件:继承、重写、向上转型
- 多态的实现方式
1.继承父类进行方法重写
2.抽象类和抽象方法
3.接口实现
抽象类
抽象类的实现规则:
用 abstract 修饰符定义抽象类
用 abstract 修饰符定义抽象方法,只用声明,不需要实现
包含抽象方法的类就是抽象类
抽象类中可以包含普通的方法,也可以没有抽象方法
抽象类的对象不能直接创建,通常是定义引用变量指向子类对象。
使用抽象类:
1.自上而下的设计时,只需知道父类需要实现哪些功能,不需关心子类具体的实现方式;
2.从多个类中抽象出子类模版。
// TelePhone.java
public abstract class TelePhone{
public abstract void call();
public abstract void message();
}
// CellPhone.java
public class CellPhone extends TelePhone{
@Override
public void call(){
System.out.println("打电话");
}
@Override
public void message(){
System.out.println("发短信");
}
public static void main(String[] args){
CellPhone c = new CellPhone();
c.call();
c.message();
}
}
接口
用于描述类所具有的功能,而不提供实现的方式。
修饰符 interface 接口名称 [extends 其它接口名]{
// 声明变量
// 抽象方法
}
// 多继承实现方式
修饰符 interface A extends 接口1,接口2{
}
修饰符 class A implements 接口1, 接口2{
}
// Animal.java
interface Animal{
int y = 7;
public void eat();
public void run();
}
// Dog.java
public class Dog implements Animal{
public void eat(){
System.out.println("Dog eat");
}
public void run(){
System.out.println("Dog run");
}
public static void main(String[] args){
Dog d = new Dog();
System.out.println(d.y);
d.eat();
d.run();
}
}
内部类
将一个类定义到另一个类的内部。与之对应的类为外部类。作用:
1.更好的封装;
2.内部类可以访问外部类的所有变量;
3.有些功能使用内部类可以更好的实现;
4.内部类允许继承多个非接口类型。
内部类是一个编译时的概念,一旦编译成功,就会成为完全不同的两类。对于一个名为 outer 的外部类和其内部定义的名为 inner 的内部类。编译完成后出现 outer.class 和 outer$inner.class 两类。所以内部类的成员变量/方法名可以和外部类的相同。
- 成员内部类
// Animal.java
public class Animal{
private int ID = 0;
// 内部类 Dog
public class Dog{
String name = "dog";
public void bark(){
System.out.println("汪");
}
}
public static void main(String[] args){
Animal ani = new Animal();
Dog dog = ani.new Dog();
dog.bark();
}
}
1.Dog相当于Animal的一个成员变量;
2.Dog的方法可以访问Animal的所有属性和方法;
3.成员内部类的实例化:内部类 对象名 = 外部类.new 内部类();
4.如内部类与外部类有相同属性或方法,内部类默认优先访问内部类的属性或方法。如需访问外部类的属性或方法,使用this
关键字;
5.成员内部类不能含有 static 的变量和方法,因为成员内部类需要先创建了外部类,才能创建它自己。
- 静态内部类
嵌入类。
// Animal.java
public class Animal{
private int legNum = 4;
static String ID = "20200001";
static int age = 3;
public static class Dog{
String ID = "20200002";
public void printInfo(){
System.out.println("Dog ID:" + ID);
System.out.println("Animal age:" + age);
System.out.println("Animal ID:" + Animal.ID);
System.out.println("Animal legNum:" + new Animal().legNum);
}
}
public static void main(String[] args){
Dog dog = new Dog();
dog.printInfo();
}
}
1.静态内部类成员名与外部静态成员名相同时,静态内部类优先访问自身的成员:成员
;
2.外部类的静态成员名与静态内部类不同名时,静态内部类可直接访问:成员
;
3.静态内部类访问外部类的静态成员:外部类名.静态成员
;
4.静态内部类访问外部类的非静态成员:new 外部类().成员
。
5.静态内部类可以直接实例化:静态内部类 对象 = new 静态内部类()
.
- 局部内部类
内部类定义在方法和作用域内。
// Animal.java
public class Animal{
// 定义在方法内
public void printInfo(){
final String NAME = "Animal";
class Dog{
String ID = "20200002";
public void print(){
System.out.println("Dog ID:" + ID);
System.out.println("printInfo() NAME:" + NAME);
}
}
Dog dog = new Dog();
dog.print();
}
// 定义在作用域内
public void printInfo2(boolean b){
if (b){
final String NAME = "Animal_";
class Dog{
String ID = "20200002_";
public void print(){
System.out.println("Dog ID:" + ID);
System.out.println("printInfo2() NAME:" + NAME);
}
}
Dog dog = new Dog();
dog.print();
}
}
// test
public static void main(String[] args){
Animal ani = new Animal();
// 方法内
ani.printInfo();
// 作用域内
ani.printInfo2(true);
}
}
如何理解定义在作用域内?
- 匿名内部类
没有名字的内部类,只能使用一次,通常用来简化代码。
使用前提:必须继承一个父类,或实现一个接口
。
// Outer.java
public class Outer{
public Inner getInner(final String name, String city){
return new Inner(){
private String nameStr = name;
public String getName(){
return nameStr;
}
};
}
public static void main(String[] args){
Outer outer = new Outer();
Inner inner = outer.getInner("Inner", "NewYork");
System.out.println(inner.getName());
}
}
interface Inner{
String getName();
}
1.匿名类不能加访问修饰符;
2.new 匿名类(),要先定义,否则会报错;
3.当所匿名类所在方法的形参需要在匿名类内部使用时,必需使用final
;
// 因匿名内部类无名字,默认无参构造函数
// 带参构造函数的实现
public Inner getInner(final String name, string city){
return new Inner(name, city){
private String nameStr = name;
public String getName(){
return nameStr;
}
};
}