JAVA面向对象
在程序中创建对象,首先需要定义一个类,类是对象的抽象,它用于描述一组对象的共同特征和行为。类中可以定义成员变量和成员方法。其中成员变量用于描述对象的特征,也被称作属性,成员方法用于描述对象的行为,可以简称方法
在JAVA中定义在类中的变量被称作成员变量,定义在方法中的变量被称作局部变量,如果某个方法中定义的局部变量与成员变量同名,这种情况是允许的,此时方法中通过变量名访问到的是局部变量,而并非成员变量
对象的创建和使用
类名 对象名称=new 类名();
创建Person类的实例对象
Person p=new Person();
上面中 new Person() 用于创建Person类的一个实例对象 Person p 则是声明一个Person类型的变量p 中间的等号用于将Person对象在内存中的地址赋值给变量p
这样变量便持有了对象的引用
创建Person对象后 可以通过对象的引用来访问对象所有的成员
对象引用.对象成员
Person p1=new Person();
Person p2=new Person();
p1.age=18;
p1.speak();
p2.speak();
注意:
当没有任何变量引用这个对象时,它将成为垃圾对象,不能被使用
p2=null;
再次调用
p2.speak();时会抛出空指针异常
在JAVA中 null是一种特殊的常量,当一个变量的值为null时,则表示该变量不指向任何一个对象。上面中p2=null那么被p2所引用的Person对象就会失去引用,成为垃圾对象
类的封装
类的封装是指在定义一个类时,将类中的属性私用化,即使用private关键字来修饰
私用属性只能在它所在类中被访问,如果外界想要访问私有属性,需要提供一些使用public修饰的公有方法,其中包括用于获取属性值的getXxx方法和设置属性值的setXxx方法。
class Student{
private String name;
private int age;
下面是公有的getXxx和setXxx方法
public String getName(){
return name;
}
public void setName(String stuName){
name=stuName;
}
public int getAge(){
return age;
}
public void setAge(int stuAge){
if(stuAge<=0){
System.out.println("对不起,你输入的年龄不合法...");
}elss{
age=stuAge;
}
}
public void introduce(){
System.out.println("大家好,我叫"+name+",我今年"+age+"岁!");
}
}
public class Example04{
public static void main(String[] args){
Student stu=new Student();
stu.setAge(-30);
stu.setName("韩强");
stu.introduce();
}
}
构造方法
满足下面条件才可以称作构造方法{
1.方法名和类名相同
2.在方法名前面没有返回类型的声明
3.在方法中不能使用return语句返回一个值,但是可以单独写return语句来作为方法的结束
class Person{
public Person(){
System.out.println("无参数的构造方法被调用了....");
}
}
public class Example04{
public static void main(String[] args){
Person p1=new Person();
}
}
class Person{
int age;
public Person(int a){
age=a;
}
public void speak(){
System.out.println("今年我已经"+age+"岁了!");
}
}
public class Example05{
public static void main(String[] args){
Person p1=new Person(20);
p1.speak();
}
}
构造方法的重载:
根据传入的参数的不同和参数类似不同可以对构造方法进行重载
注意:
在JAVA中的每个类都至少有一个构造方法,如果在一个类中没有定义构造方法,系统会自动为这个类创建一个默认的构造方法,这个默认的构造方法没有参数,在其方法体中没有任何代码,即什么也不做
第一种:
class Person{
}
第二种:
class Person{
public Person(){
}
}
对于第一种写法,类中虽然没有声明构造方法,但是仍然可以用new Person()语句来创建Person类的实例对象,由于系统提供的构造方法往往不能满足需求,因此,可以自己在类中定义构造方法,一旦为该类定义了构造方法,系统就不再提供默认的构造方法了
在一个类中如果定义了有参的构造方法,最好再定义一个无参的构造方法,可以避免出现要调用无参数的构造方法时候没有而报错
为了方便实例化对象,构造方法通常会使用public来修饰
this关键字
三种常见用法
1.通过this关键字可以明确地去访问一个类的成员变量,解决与局部变量名称冲突问题
2.通过this关键字调用成员方法
3。构造方法是再实例化对象时被JAVA虚拟机自动调用的,在程序中不能像调用其他方法一样去调用构造方法,但是可以在一个构造方法中使用this([参数1,参数2....])的形式来调用其他的构造方法
如下:
class Person{
public Person(){
System.out.println("无参数的构造方法被调用了...");
}
public Person (String name){
this();
System.out.println("有参的构造方法被调用了...")
}
}
public class Example10{
public static void main(String[] args){
Person p=new Person("itcast");
}
}
在使用this调用类的构造方法时,注意;
1.只能在构造方法中使用this调用其他的构造方法,不能在成员方法中使用
2.在构造方法中使用this调用构造方法的语句必须位于第一行,且只能出现一次
public Person(){
String name="小韩";
this(name);
}
3/不能在一个类的两个构造方法中使用this互相调用,下面的写法编译会报错
class Person{
public Person(){
this("小韩");
System.out.println("无参数的构造方法被调用了....");
}
public Person (String name){
this()
System.out.println("有参数的构造方法被调用了...");
}
}
垃圾回收机制
除了JAVA虚拟机自动垃圾回收外,还可以通过调用System,gc();方法来通知JAVA虚拟机立即进行垃圾回收,当一个对象在内存中被释放时,它的finalize()方法会自动调用,因此可以通过finalize()方法观察对象何时被释放
class Person{
public void finalize(){
System.out.println("对象将被作为垃圾回收...");
}
}
public class Example06{
public static void main(String[] args){
Person p1=new Person();
Person p2=new Person();
p1=null;
p2=nulll
System,gc();
for(int i=0;i<1000000;i++){
}
}
}
静态变量
在JAVA类中,可以使用static 关键字来修饰成员变量,该变量被称作静态变量,监听变量被所有实例共享,可以使用”类名.变量名“的形式访问
class Student{
static String schoolName;
}
public class Example01{
public static void main(String[] args){
Student stu1=new Student();
Student stu2=new Student();
Student.schoolName="传播智客"
System.out.println("我的学校是:"+stu1.schoolName);
System.out.println("我的学校是:"+stu2.schoolName);
}
}
static关键字只能用于修饰成员变量,不能用于修饰局部变量,否则编译会报错
public class Student{
public void study(){
static int num=10;
}
}
静态方法:
类名.方法名的方式访问
class Person{
public static void sayHello(){
System.out.println("hello");
}
}
class Exampl03{
public static void main(String[] args){
Person.sayHello();
Person p=new Person();
p.sayHello();
}
注意:在一个静态方法中只能访问用static修饰的成员,原因在于没有被static修饰的成员需要先创建对象才能访问,而静态方法在被调用时可以不创建任何对象
静态代码块:
class Examp14{
static{
System.out.println("测试类的静态代码块执行了");
}
public static void main(String[] args){
Person p1=new Person();
Person p2=new Person();
}
}
class Person{
static{
System.out.println("Person类中的静态代码块执行了");
}
}
成员内部类:
class Outer{
private int num=4;
public void test(){
Inner inner=new Inner();
inner.show();
}
class Inner{
void show(){
System.out.println("num="+num);
}
}
}
public class Example15{
public static void main(String[] args){
Outer outer =new Outer();
outer.test();
}
}
上面可以看出内部类可以在外部类中被使用,并能访问外部类的成员
想要外部类去访问内部类,则需要通过外部类对象去创建内部类对象,创建内部类对象如下:
外部类.内部类 变量名=new 外部类名().new 内部类名
public class Example16{
public static void main(String[] args){
Outer.Inner inner=new Outer().new Inner();
inner.show();
}
}
注意:
如果内部类被声明为私用,,外界将无法访问
面向对象下
类的继承
在类的继承中需要注意:
1.JAVA中,类只支持单继承,不允许多继承,也就是说一个类只能有一个直接父类
class A{}
class B{}
class C extends A,B{}
2.多个类可以继承一个父类,例如下面情况是允许的
class A{}
class B extends A{}
class C extends A{}
3.在JAVA中多层继承是可以的,即一个类的父类可以再去继承其他另外的父类
class A{}
class B{} extends A{}
class C extends B{}
重写父类方法:
class Animal{
void shout(){
System.out.println("动物发出叫声")
}
}
class Dog extends Animal{
void shout(){
System.out.println("汪汪汪....")
}
}
public class Example02{
public static void main(String[] args){
Dog dog=new Dog();
dog.shout();
}
}
注意:
子类重写父类方法时,不能使用比父类中被重写的方法更严格的访问权限,如:父类中的方法是public的,子类的方法就不能是private的
super关键字
使用super关键字访问父类的成员变量和成员方法
super.成员变量
super.成员方法([参数1,参数2...])
class Animal{
String name="动物";
void shout(){
System.out.println("动物发出叫声");
}
}
class Dog extends Animal{
String name="犬类"
void shout(){
super.shout();
}
void printName(){
System.out.println("name="+super.name);
}
}
定义测试类
public class Example03{
public static void main(String[] args){
Dog dog=new Dog();
dog.shout();
dog.printName();
}
}
2.使用super关键字访问父类的构造方法
super([参数1,参数2....])
class Animal{
定义Animal类的有参的构造方法
public Animal(String name){
System.out.println("我是一只"+name);
}
}
class Dog extends Animal{
public Dog(){
super("沙皮狗");
}
}
定义测试类
public class Example04{
public static void main(String[] args){
Dog dog=new Dog();
}
通过调用父类的构造方法的代码必须位于子类构造方法的第一行,并且只能出现一次
在子类的构造方法通过super指定调用父类的那个构造方法,如果没有指定,在实例化子类对象时会自动调用父类无参的构造方法,为了防止父类定义了有参的构造方法
在子类中没有用super指向父类有参的构造方法,而出现报错,可以在子类中调用父类中已有的构造方法,也可以选择在父类中定义无参数的构造方法
注意;
定义一个类时,如果没有特殊需求,尽量在类中定义一个无参的构造方法,避免被继承时出现错误
final关键字
特性:
fianl修饰的类不能被继承
fianl修饰的方法不能被子类重写
final 修饰的变量(成员变量和局部变量)是常量,只能赋值一次
抽象类和接口
抽象方法:
abstract void shout();
当一个类中包含抽象方法,该类必须使用abstract 关键字修饰,使用abstract关键字修饰的类为抽象类
abstract class Animal{
abstract int shout();
}
注意:包含抽象类方法的类必须声明为抽象类,但是抽象类可以不包含任何抽象方法,只需要使用abstract关键字来修饰即可,另外抽象类是不可以被实例化的,因为抽象类中有可能包含抽象方法,抽象方法是没有方法体的,不可以被调用,如果想调用抽象类中定义的方法,则需要创建一个子类,在子类中将抽象类中的抽象方法进行实现
abstract class Animal{
abstract void shout();
}
class Dog extends Animal{
void shout(){
System.out.println("汪汪汪...")
}
}
public class Example10{
public static void main(String[] args){
Dog dog=new Dog();
dog.shout()
}
}
如果一个抽象类中的所有方法都是抽象的,则可以将这个类用另外一种方式来定义,即接口,接口是由常量和抽象方法组成的特殊类,是对抽象类的进一步抽象
语句格式:
[public] interface 接口名 [extends 接口1,接口2]{
[public] [static] [final] 数据类型 常量名=常量值;
[public] [abstract] 返回值 抽象方法名(参数列表)
}
一个接口可以有多个父接口,它们之间用逗号隔开,JAVA使用接口的目的是为了克服单继承的限制,因为一个类只能有一个父类,而一个类可以实现多个接口。
public static final 即全局变量 方法为:public abstract
可以使用implements关键字实现接口中有的方法
在implements子句中要使用格式
[<修饰符>] class <类名> [extends <超类名>] [implements <接口1>,<接口2>,.....]
案例:
interface Animal{
String ANIMAL_BEHAVIOR="动物的行为";
void breathe();
void run();
}
class Dog implements Animal{
public void breathe(){
System.out.println(ANIMAL_BEHAVIOR+":"+"狗在呼吸")
}
public void run(){
System.out.println(ANIMAL_BEHAVIOR+":"+"狗在奔跑")
}
}
public class Example11{
public static void main(String[] args[]){
Dog dog =new Dog();
dog.breathe();
dog.run();
}
}
注意:
一个类一个接口,必须给出接口中所有方法的实现,如果不能实现某方法,必须写出一个空方法
还可以定义一个接口使用extends 关键字去继承另一个接口
interface Animal{
String ANIMAL_BEHAVIOR="动物的行为";
void breathe();
void run();
}
interface LandAnimal extends Animal{
void liveOnLand();
}
class Dog implements Animal{
public void breathe(){
System.out.println(ANIMAL_BEHAVIOR+":"+"狗在呼吸")
}
public void run(){
System.out.println(ANIMAL_BEHAVIOR+":"+"狗在奔跑")
}
public void liveOnLand(){
System.out.println("狗是陆地上的动物...")
}
}
public class Example12{
public static void main(String[] args[]){
Dog dog =new Dog();
dog.breathe();
dog.run();
dog.liveOnLand();
}
}
接口的特点:
1.接口中的方法都是抽象的,不能实例化对象
2.接口中的属性只能是常量
3.当一个类实现接口时,如果这个类是抽象类,则实现接口中的部分方法即可,否则需要实现接口中的所有方法
4.一个类通过implements关键字实现接口时,可以实现多个接口,被实现的多个接口之间要用逗号隔开
如下:
Interface Run{
程序代码....
}
Interface Fly{
程序代码....
}
class Bird implement Run,Fly{
程序代码....
}
5.一个接口可以通过extends 关键字继承多个接口,接口之间要用逗号隔开
如下:
Interface Running{
程序代码....
}
Interface Flying{
程序代码....
}
Interface Eating extends Running,Flying{
程序代码....
}
6.一个类在继承另一个类的同时还可以实现接口,此时,extends 关键字必须位于implements关键字之前
如下;
class Dog extends Canidae implements Animal{
程序代码....
}