前言:面向对象与面向过程区别,面向过程强调的是功能行为,面向对象,将功能封装进对象,强调具备了功能的对象。
1.Java类及类成员
(1)类的定义
类的语法格式:
public class Person{
private int age ; //声明私有变量 age
public void showAge(int i) { //声明方法showAge( )
age = i;
}
}
定义类时考虑的问题:
- 定义类(考虑修饰符、类名)
- 编写类的属性(考虑修饰符、属性类型、属性名、初始化值)
- 编写类的方法(考虑修饰符、返回值类型、方法名、形参等)
权限修饰符:
对象的内存解析
例一:
例二:
(2)属性
语法格式:
例:
成员变量与局部变量的存储位置和初始化问题:
- 局部变量存储在当前函数的栈中,new出来的结构(如数组和对象)存在当前JVM实例的堆中,成员变量最终是以对象形式存在堆中
- 存在堆中的变量默认是有初始化,而存在栈中的变量默认是没有初始化,需要显示初始化。
成员变量默认初始化值:
(3)方法
语法格式:
说明:
例:
public class Person{
private int age;
public int getAge() { //声明方法getAge
return age;
}
public void setAge(int i) { //声明方法setAge
age = i;
}
}
注意: 在static方法访问非static,编译不通过。
方法重载:
在同一个类中,具有相同的方法名但参数列表不同。与返回值类型无关。
例:
//三个方法相互重载
int add(int x,int y){
return x+y;
}
int add(int x,int y,int z){
return x+y+z;
}
double add(double x,double y){
return x+y;
}
方法的重用写(override):
子类对从父类继承过来的方法进行重写叫做重写、重置、覆盖。
要求:
- 重写方法必须和被重写方法具有相同的方法名称、参数列表。
- 重写的方法的返回值类型不能大于被重写的方法的返回值类型
- 重写方法使用的访问权限不能小于被重写方法的访问权限。
- 子类不能重写父类中声明为private权限的方法
- 子类方法抛出的异常不能大于父类被重写方法的异常
例:
方法的参数传递:
方法的参数传递方式只有一种:值传递
例:
基本数据类型的参数传递:
引用数据类型的参数传递:
面试题
答案为:B
答案:
// 在不改变原本题目的前提下,如何写这个函数才能在main函数中输出a=100,b=200?
//法一:
public static void test(int a, int b) {
a = a*10;
b = b*20;
System.out.println(a);
System.out.println(b);
System.exit(0); //提前结束程序,让main方法后面的语句无法执行。
}
法二:
private static void test(int a, int b) {
PrintStream printStream = new PrintStream(System.out) {
@Override
public void println(String x) {//覆写println方法
if ("a=10".equals(x)) {
x = "a=100";
} else if ("b=20".equals(x)) {
x = "b=200";
}
super.println(x);
}
};
System.setOut(printStream);
}
可变个数的形参:
方法形参在指定数据类型后是可变多个的,它的使用与数组一样,但它的声明必须放在形参列表的最后。
声明方式:方法名(参数的类型名…参数名)
public static void test(int a ,String…books);
//其等同于:
public static void test(int a ,String[] books);
(4)构造器
构造器的作用:创建对象、给对象进行初始化。
定义格式:
例:
public class Animal {
private int legs;
public Animal() { //构造器
legs = 4;
}
}
构造器相互调用:https://blog.csdn.net/xiaojingfirst/article/details/91351168
注意:
- Java语言中,每个类都至少有一个构造器
- 默认构造器的修饰符与所属类的修饰符一致
- 一旦显式定义了构造器,则系统不再提供默认构造器
- 一个类可以创建多个重载的构造器
- 父类的构造器不可被子类继承
- 在子类的构造器中如果没有显示地调用父类的构造器,那么默认会在子类构造器开头调用父类的无参构造器。
例:
class Father{
Father(){
System.out.println("这是父类的构造器!");
}
}
public class Son extends Father{
public Son(){
System.out.println("这子类的构造器!");
}
// public Son(){ //这个构造器和上面的是等价的。
// super();
// System.out.println("这子类的构造器!");
// }
public static void main(String[] args) {
new Son();
}
}
运行输出:
(5)JavaBean
JavaBean是一种Java语言写成的可重用的组件。
JavaBean的要求:
- 类是公共的
- 有一个无参的公共的构造器
- 有属性,且有对应的get、set方法
例:
public class JavaBeanTest{
private String name; //属性一般定义为private
private int age;
public JavaBeanTest(){}
public int getAge(){
return age;
}
public void setAge(int age){
this.age = age;
}
public String getName(){
return name;
}
public void setName(String name){
this.name = name;
}
(6)匿名对象
在创建对象时不创建对象的句柄,如new Person(),没有用变量来接受对象的句柄。
匿名对象的使用场景:
- 如果对一个对象只需要进行一次方法调用,那么就可以使用匿名对象。
- 我们经常将匿名对象作为实参传递给一个方法调用。
2.面向对象的三大特征
封装性:
Java中通过将数据声明私有的(private),再提供公共的(public)方法:getXxx()和setXxx()实现对属性的操作。通过封装可以实现:
- 隐藏具体实现的细节
- 可以然使用者只能按照指定的方法来访问数据。
例:
public class Animal{
private int legs;//将属性legs定义为private,只能被Animal类内部访问
public void setLegs(int i){ //在这里定义方法 eat() 和 move()
if (i != 0 && i != 2 && i != 4){
System.out.println("Wrong number of legs!");
return;
}
legs=i;
}
public int getLegs(){
return legs;
}
}
public class Zoo{
public static void main(String args[]){
Animal xb=new Animal();
xb.setLegs(4); //xb.setLegs(-1000);
xb.legs=-1000; //非法
System.out.println(xb.getLegs());
}
}
继承:
将公共的属性和方法提取出来单独构成一个类,子类通过继承(extends)父类获的父类的属性和方法,并在此基础上进行扩展,提高了代码的复用性。
class Person{//父类
private String name;
private int age;
public String toString() {
return "Person [name=" + name + ", age=" + age + "]";
}
}
public class Student extends Person{ //子类
private String stuNum;
}
注意:Java只支持单继承,不允许多重继承,所有子类的构造器都会默认访问父类的无参构造器,所以父类中必须确保有无参构造器(如果显式定义构造器,系统将不会再提供无参构造器),而且如果在子类构造器显式调用父类的构造器必须放在构造器的第一行。
多态性:
Java引用变量有两个类型:编译时类型和运行时类型。编译时类型有声明该变量时使用的类型决定,运行时类型有实际赋给该变量的对象决定。但编译类型和运行类型不同时,就出现多态。
在Java中的多态有:
- 方法的重载(overload)和重写(overwrite).
- 对象的多态性(可以应用在抽象类和接口),子类的对象可以替代父类的对象使用。如Person p =new Student();
例子:
注意:一个引用类型变量如果声明为父类的类型,但实际引用的是子类的对象,那么该变量就不能在访问子类中添加的属性和方法(强制转换为子类可以访问)。
例:
instanceof 操作符:
x instanceof A:判断x是否为类A的对象,放回值为boolean类型,要求x所属的类于类A必须是子类或父类的关系,否则编译无法通过。如果x属于类A的子类B,x instanceof A值也为true.
class A{}
class B extends A{}
public class C {
public static void main(String[] args) {
A a = new A();
B b = new B();
C c = new C();
A d = new B();
System.out.println((a instanceof A));//是A类的对象,true
System.out.println((b instanceof A));//是A类的子类对象,true
System.out.println((d instanceof B));//虽然d是B的引用,编译时认为A类,true
System.out.println((c instanceof A));//编译无法通过
}
}
对象类型转换:
基本数据类型的转换:
- 自动类型转换:小的数据类型可以自动转换成大的数据类型,如long g = 20;
- 强制类型转换:可以把大的数据类型强制转换成小的数据类型,如int a=(int)1200L
Java对象的强制类型转换称为改造
- 从子类到父类的数据类型转换可以自动进行。
- 从父类到子类的类型转换必须通过强制类型转换实现
- 无继承关系的引用类型间的转换是非法的(改造前可以用instanceof测试对象的所属类)
public class ConversionTest{
public static void main(String[] args) {
double d = 13.4;
long l = (long)d;
System.out.println(l);
int in = 5;
//boolean b = (boolean)in;
Object obj = "Hello";
String objStr = (String)obj;
System.out.println(objStr);
Object objPri = new Integer(5);
//所以下面代码运行时引发ClassCastException异常
String str = (String)objPri;
}
}
public class Test{
public void method(Person e) { //设Person类中没有getschool() 方法
// System.out.pritnln(e.getschool()); //非法,编译时错误
if(e instanceof Student){
Student me = (Student)e; //将e强制转换为Student类型
System.out.pritnln(me.getschool());
}
}
public static void main(Stirng args[]){
Test t = new Test();
Student m = new Student();
t.method(m);
}
}
3.其他关键字
(1)package关键词:
package语句作为Java源文件的第一条语句,指明文件中定义的类所在的包。
格式:package 顶层包名.子包名;如:package shopping.reports; 使用包方便过来大型软件系统,将语义相近的类放到一个包中,如MVC的设计模式。
(2)import关键词:
import用来引入指定包层次下所需要的类或全部类(.)
语法格式:import 包名[.子包名…]. <类名 |>
例:
import p1.Test; //import p1.*;表示引入p1包中的所有类
public class TestPackage{
public static void main(String args[]){
Test t = new Test(); //Test类在p1包中定义
t.display();
}
}
注意:如果导入的类或接口是java.lang包下的,或者是当前的包下的,则可以省略此import语句。
JDK主要包的介绍:
(3)extends关键词:
当一个类要继承另外一个类时使用extends关键字。
(4)this关键词:
this表示当前对象,可以调用类的属性、方法和构造器。
使用场景:
- 当形参与成员变量重名时,如果在方法内部需要使用成员变量,必须添加this来表明该变量时类成员
- 在任意方法内,如果使用当前类的成员变量或成员方法可以在其前面添加this,增强程序的阅读性
- this可以作为一个类中,构造器相互调用的特殊格式(this()必须放在首行)
例:
class Person{ // 定义Person类
private String name ;
private int age ;
public Person(){ // 无参构造器
}
public Person(String name){
this(); // 调用本类中的无参构造器
this.name = name ;
}
public Person(String name,int age){
this.name = name ; //形参与成员变量同名,需要用this区分。
this.age = age ;
}
public String getInfo(){
return "姓名:" + name + ",年龄:" + age ;
}
}
(5)super关键词:
super关键词作用:
- 用于访问父类中定义的属性(出现同名冲突时)。
- 调用访问父类中定义的方法
- 在子类构造器中调用父类的构造器
class Person{
private String name;
private int age;
Person(){}
Person(String name,int age){
this.name = name;
this.age = age;
}
}
public Student extends Person{
private String stuNum;
public Student(String name,int age,String stuNum){
super(name,age);
this.stuNum = stuNum;
}
}