JavaSE
面向对象
- 文件名
- 在一个java文件写两个类:一个基本类,一个测试类
- 对象
- 类名 对象名 = new 类名( );
- 使用成员变量
- 对象名.变量名
- 使用成员方法
- 对象名.方法名(...)
class Demo1_student{
public static void main(String [] args) {
Student s = new Student();
/*
* 1. 声明一个引用变量(栈),栈中开辟s
* 2. 通过new关键字 在 堆中开辟 存储 Student对象
* 3. 通过赋值将堆Student地址传给栈中的s
* */
s.name = "Mephisto";
s.age = 14;
s.gender = "Male";
s.study();
s.sleep();
System.out.println("学生姓名:" + s.name + " "+ "学生性别: "+ s.gender);
}
}
class Student {
String name;
int age;
String gender;
public void study() {
System.out.println("学生学习");
}
public void sleep() {
System.out.println("学生睡觉");
}
}
成员变量和局部变量区别:
-
在类中的位置不同:
- 成员变量:在类中方法外
- 局部变量:在方法定义中或方法声明上
-
在内存中的位置不同:
- 成员变量: 在堆内存(成员变量属于对象, 对象进 堆内存)
- 局部变量: 在栈内存(局部变量属于方法, 方法进 栈内存)
-
生命周期不同
- 成员变量: 随着对象的创建而存在,随着对象的消失而消失
- 局部变量: 随着方法的调用而存在,随着方法的调用完毕而消失
-
初始化值不同
- 成员变量有默认的初始化值
- 局部变量没有默认的初始化值, 必须定义,赋值,然后才能使用
-
注意事项
- 局部变量名称可以和成员变量名称一样,在方法中使用的时候,采用的就是就近原则
- 基本数据类型变量包括 byte, short, int , long, float, double, boolean, char
- 引用数据类型变量包括 数组 类 接口 枚举
面向对象(如何调用对象方法的形式参数是类名)
public class Demo3 {
public static void main(String [] args) {
print(10);
Demo_Student s = new Demo_Student(); //创建对象,并将对象的地址值赋值给s
print(s);
}
public static void print(int x) { // 基本数据类型当作形式参数
System.out.println(x);
}
public static void print(Demo_Student s) { // 引用数据类型当作形式参数
s.name = "Mephisto";
s.age = 22;
s.speak();
}
}
/*
* 方法的参数名是类名 public void print(Demo_Student s){} // print(new Student));
* 一个方法的形式参数是一个类类型(引用数据类型), 需要的是该类的对象;
* */
class Demo_Student{
String name;
int age;
public void speak() {
System.out.println(name + " " + age);
}
}
面向对象(匿名对象)
/*
* 匿名对象: 没有名字的对象
* 匿名对象应用场景: 调用方法, 仅仅调用一次的时候 , 匿名调用节省代码
* 调用多次的时候不合适, 匿名对象调用完毕就是垃圾, 可以被垃圾回收器回收
* 匿名对象可以作为实际参数传递
*/
public class Demo4 {
public static void main(String [] args) {
/*
Car c1 = new Car(); // 创建有名字的对象
c1.run();
new Car().run(); // 匿名对象调用方法 , 对方法的一次调用 每次调用产生多个对象
*/
// 匿名对象是否可以调用属性并赋值? 有什么意义
/*
* 匿名对象可以调用属性,但是没有意义, 因为调用之后就变成了垃圾
* 如果调用还是用有名字的对象
new Car().color = "red";
new Car().run();
*/
/*
Car c1 = new Car();
c1.color = "red";
c1.run();
Car c2 = new Car();
c2.color = "yellow";
c2.run();
*/
/*
Car c1 = new Car();
method(c1);
Car c2 = new Car();
method(c2);
*/
// 匿名对象可以作为实际参数传递
method(new Car());
method(new Car());
}
// 抽取方法提高代码复用性
public static void method(Car cc) {
cc.color = "red";
cc.run();
}
}
class Car{
String color;
public void run() {
System.out.println(color + "车运行起来了");
}
}
面向对象(封装)
- 封装概述
- 是指隐藏对象的属性和实现细节, 仅对外公开访问方式
- 封装好处
- 隐藏实现细节, 提供公共的访问方式
- 提高了代码的复用性
- 提高安全性
- 封装原则
- 将不需要对外提供的内容都隐藏起来
- 把属性隐藏提供公共方法对其访问
- private关键字特点
- 是一个权限修饰符
- 可以修饰成员变量和成员方法
- 被其修饰的成员只能在本类中被访问
package learn_javaSe;
/*
* 封装和private的应用:
* 把成员变量用private修饰
* 提供对应的getXXX()和setXXX()方法
* private仅仅是封装的一种形式体现, 不能说封装就是私有
*/
public class Demo5 {
public static void main(String[] args) {
// TODO Auto-generated method stub
Demo5_Person p1 = new Demo5_Person();
p1.name = "Mephisto";
/*
p1.age = -22;
p1.speak();
*/
p1.setAge(-22);
System.out.println(p1.getAge());
}
}
class Demo5_Person{
String name; // 姓名
private int age; // 年龄
public void setAge(int a) { // 设置年龄
if( a> 0 && a < 200)
age = a;
else
System.out.println("请输入正常的年龄");
}
public int getAge() { // 获取年龄
return age;
}
public void speak() {
System.out.println(name + " " + age);
}
}
面向对象(this关键字)
/*
* this关键字特点: 代表当前对象的引用
* 区分成员变量和局部变量
*/
public class Demo6 {
public static void main(String[] args) {
// TODO Auto-generated method stub
Demo6_person p = new Demo6_person();
p.setName("Mephisto");
p.setAge(15);
System.out.println(p.getName() + " " + p.getAge());
Demo6_person p2 = new Demo6_person();
p2.setName("Vincent");
p2.setAge(25);
System.out.println(p2.getName() + " " + p2.getAge());
}
}
class Demo6_person{
private String name; // 姓名
private int age; // 年龄
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setAge(int age) { // 设置年龄
if( age> 0 && age < 200)
this.age = age;
else
System.out.println("请输入正常的年龄");
}
public int getAge() { // 获取年龄
return age;
}
}
手机类
package learn_javaSe;
public class Demo7 {
public static void main(String[] args) {
Demo7_Phone p =new Demo7_Phone();
p.setBrand("魅族");
p.setPrice(2499);
System.out.println(p.getBrand() + " " + p.getPrice());
p.call();
p.playGame();
p.sendMessage();
}
}
/*
* 手机类:
* 属性: 品牌brand 价格 price
* 行为: 打电话call, 发信息 sendMessage 玩游戏 playGame
*/
class Demo7_Phone{ // java bean
private String brand; // 品牌
private int price; //价格
public void setBrand(String brand) { // 设置品牌
this.brand = brand;
}
public String getBrand() { //获取品牌
return this.brand; // this.可以省略, 系统默认加上
}
public void setPrice(int price) { // 设置价格
this.price = price;
}
public int getPrice() { // 获取价格
return price;
}
public void call() {
System.out.println("打电话");
}
public void sendMessage() {
System.out.println("发短信");
}
public void playGame() {
System.out.println("玩游戏");
}
}
构造方法
构造方法: 给对象的数据(属性) 进行初始化
构造方法格式和特点:
方法名与类名相同(大小也和类名一致)
没有返回值类型, 连void也没有
没有具体的返回值
return;
package learn_javaSe;
public class Demo8 {
public static void main(String[] args) {
// TODO Auto-generated method stub
Demo8_Person p = new Demo8_Person(); // 在创建对象的时候就已经调用了构造方法
// p.Demo8_Person // 构造方法不能通过对象调用
p.show();
}
}
class Demo8_Person{
private String name;
private int age;
// 构造方法
public Demo8_Person(){
// System.out.println("Hello world!");
// return; // 构造方法也是有return语句的 格式: return;
name = "Mephisto";
age = 10;
return;
}
public void show() {
System.out.println(name + " " + age);
}
}
面向对象(构造方法的重载及注意事项)
- 构造方法的重载:方法名相同,与返回值类型无关(构造方法没有返回值),只看参数列表
- 注意事项
- 如果没有给出构造方法, 系统将默认提供一个无参构造方法
- 如果给出了构造方法,系统将不再提供默认的无参构造方法
- 还想使用无参构造方法,需要自己给出
public class Demo9 {
public static void main(String [] args) {
Demo9_Person p1 = new Demo9_Person();
p1.show();
System.out.println("----------------------");
Demo9_Person p2 = new Demo9_Person("Mephisto",18);
p2.show();
Demo9_Person p3 = new Demo9_Person("Vincent",17);
p3.show();
}
}
class Demo9_Person{
private String name;
private int age;
public Demo9_Person() {
System.out.println("空参的构造参数");
}
public Demo9_Person(String name,int age) {
this.name = name;
this.age = age;
System.out.println("有参的构造方法");
}
public void show() {
System.out.println(name + " " + age);
}
}
构造方法和setXXX()方法区别
public class Demo10 {
public static void main(String[] args) {
Demo10_Person p1 = new Demo10_Person("Mephisto",18);
// p1 = new Demo10_Person("李四",19); // 重新创建的新对象,不是对原对象的修改,将原对象变成垃圾
System.out.println(p1.getName()+" "+ p1.getAge());
System.out.println("============================");
Demo10_Person p2= new Demo10_Person();
p2.setName("Vincent");
p2.setAge(24);
p2.setName("张三");
System.out.println(p2.getName()+" "+ p2.getAge());
}
}
/*
* 构造方法 给属性进行初始化
* setXXX()方法 修改属性值, 更加灵活
*/
class Demo10_Person{
private String name;
private int age;
public Demo10_Person() {
}
public Demo10_Person(String name, int age) {
this.name = name;
this.age = age;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setAge(int age) {
this.age = age;
}
public int getAge() {
return age;
}
}
Student s = new Student();
- Student.class加载进内存
- 声明一个Student类型引用
- 在堆内存创建对象
- 给对象中属性默认初始化值
- 属性进行显示初始化
- 构造方法进栈, 对对象中的属性赋值, 构造方法弹栈
- 将对象的地址值赋值给s
static
static关键字的特点:
- 随着类的加载而加载
- 优先于对象的存在
- 被类的所有对象共享(例如班级号被全班同学共享)
- 可以通过类名调用
- 本身可以通过对象名调用
- 推荐使用类名调用
- 静态修饰的内容一般我们称其为: 与类相关的, 类成员
public class Demo16 {
public static void main(String[] args) {
/*
Demo16_Person p1 = new Demo16_Person();
p1.name = "mephisto";
p1.country = "中国";
Demo16_Person p2 = new Demo16_Person();
p2.name = "Vincent";
p1.speak();
p2.speak();
*/
Demo16_Person.country = "中国";
System.out.println(Demo16_Person.country);
}
}
class Demo16_Person{
String name;
static String country; // 静态
public void speak() {
System.out.println(name + " " + country);
}
}
static注意事项
package learn_javaSe;
public class Demo17 {
public static void main(String[] args) {
Demo17_Test demo = new Demo17_Test();
demo.print1();
}
}
/* static的注意事项
* 在静态方法中是没有this关键字的
* 静态是随着类的加载而加载,this是随着对象的创建而存在的
* 静态比对象现存在
* 静态方法只能访问静态的成员变量和静态的成员方法
* 静态方法:
* 成员变量: 只能访问静态变量
* 成员方法: 只能访问静态成员方法
*
* 非静态方法:
* 成员变量: 可以是静态的, 也可以是非静态的
* 成员方法: 可以是静态的成员方法, 也可以是非静态的成员方法
*
* 静态只能访问静态, 静态先于非静态存在
*
*/
class Demo17_Test{
int num1 = 10; // 非静态成员变量
static int num2 = 20; // 静态成员变量
public void print1() { // 非静态的成员方法, 可以访问静态的成员变量也可以访问非静态的成员变量
System.out.println(num1);
System.out.println(num2);
}
public static void print2() { // 静态成员方法
// System.out.println(num1); // 静态方法无法访问非静态成员变量
System.out.println(num2);
}
}
静态变量和成员变量的区别
静态变量也叫类变量, 成员变量也叫对象变量
- 所属不同
- 静态变量属于类, 所以也成为类变量
- 成员变量属于对象, 所以也成为实例变量( 对象变量 )
- 内存中位置不同
- 成员变量存储于方法区中的静态区
- 成员变量存储于堆内存中
- 内存出项的时间不同
- 静态变量随着类的加载而加载, 随着类的消失而消失
- 成员变量随着对象的创建而存在, 随着对象的消失而消失
- 调用不同
- 静态变量可以通过类名调用, 也可以同通过对象调用
- 成员变量只能通过对象名调用
package learn_javaSe;
public class Demo18 {
public static void main(String [] args) {
Test18 t1 = new Test18();
t1.print1();
String t2 = Test18.name2.toString(); // 静态 变量可以通过类名调用
System.out.println(t2);
}
}
class Test18{
String name1 = "Mephisto";
static String name2 = "Vincent";
public void print1() {
System.out.println(name1);
}
public void print2() {
System.out.println(name2);
}
}
main方法的格式解释
package learn_javaSe;
public class Demo19 {
public static void main(String [] args) {
/*
* public : 被jvm调用, 所以权限要足够大
* static : 被jvm调用, 不需要创建对象名, 直接类名, 调用即可
* main : 只有这样写才能被jvm识别, main不是关键字
* String [] args : 以前是用来接受键盘录入的
*
*/
System.out.println(args.length);
for(int i = 0; i < args.length; i++) {
System.out.println(args[i]);
}
}
}
如果一个类中所有方法都是静态的, 需要私有构造方法, 私有构造方法之后其他类无法创建该类的对象
文档注释(说明书)
@author 提取作者内容
@version 提取版本内容
@param 参数名称
@return 函数运行完返回的数据
javadoc -d 保存文件 -version -author XXXX.java
代码块
在java中, 使用{ }括起来的代码被称为代码块
代码块分类:
- 局部代码块 在方法中出现, 限定变量生命周期, 及早释放提高内存利用率
- 构造代码块 在类方法外出现, 多个构造方法中相同的代码放在一起, 每次调用构造都执行,并且在
构造方法前执行
- 静态代码块
- 在类中方法外出现, 加了static修饰
- 在类中方法外出现, 并加上了static修饰,用于给了类进行初始化, 在加载的时候就执行, 并且只执行一次
- 一般用于加载驱动
- 同步代码块
package learn_javaSe;
public class Demo23 {
public static void main(String[] args) {
// {
// int x = 10; // 限制变量的生命周期
// System.out.println(x);
// }
Test23 stu1 = new Test23();
System.out.println("---------------");
Test23 stu2 = new Test23("Mephisto",22);
System.out.println("---------------");
}
static {
System.out.println("主方法类中的静态代码块"); // 优先于主方法执行
}
}
class Test23{
private String name;
private int age;
public Test23() {
// study();
System.out.println("空参构造");
}
public Test23(String name, int age) {
// study();
this.name = name;
this.age = age;
System.out.println("有参构造");
}
public void setName(String name) {
this.name = name;
}
public String getName(){
return name;
}
public void setAge(int age) {
this.age = age;
}
public int getAge() {
return age;
}
{
// System.out.println("构造代码块");
study();
}
public void study() {
System.out.println("学习");
}
static {
System.out.println("静态代码块"); // 随着类的加载而加载, 且执行一次, 作用: 给类进行初始化, 一般用来加载驱动
}
}
输出结果
主方法类中的静态代码块
静态代码块
学习
空参构造
---------------
学习
有参构造
---------------
package learn_javaSe;
public class Demo24 {
static {
System.out.println("Demo24 静态代码块");
}
public static void main(String[] args) {
System.out.println("main方法");
Test24 t1 = new Test24();
Test24 t2 = new Test24();
}
}
class Test24{
static {
System.out.println("Test24 静态代码块");
}
{
System.out.println("Test24 构造代码块");
}
public Test24() {
System.out.println("Test24 构造方法");
}
}
输出结果
Demo24 静态代码块
main方法
Test24 静态代码块
Test24 构造代码块
Test24 构造方法
Test24 构造代码块
Test24 构造方法
继承(extends)
让类和类之间产生关系, 父子关系
package learn_javaSe;
public class Demo25 {
public static void main(String[] args) {
Cat c1 = new Cat();
c1.color = "red";
c1.leg = 4;
c1.eat();
c1.sleep();
c1.show();
}
}
class Animal{
String color;
int leg;
public void eat() {
System.out.println("吃饭");
}
public void sleep() {
System.out.println("睡觉");
}
public void show() {
System.out.println(color + " " + leg + " ");
}
}
class Cat extends Animal{
}
class Dog extends Animal{
}
-
继承的好处
- 提高代码的复用性
- 提高代码的维护性
- 让类与类之间产生了关系, 是多态的前提
-
继承的弊端
- 类的耦合性增强了
- 开发的原则: 高内聚, 低耦合
- 耦合: 类与类之间的关系
- 内聚: 就是自己完成某件事情的能力
-
Java中类的继承特点:
-
Java只支持单继承, 不支持多继承 , 多继承有安全隐患
- 有些语言支持多继承, 格式: extends 类1, 类2 .....
-
Java支持多层继承(继承体系)
- 使用这个体系使用最底层
- 想看共性看最顶层
-
package learn_javaSe;
public class Demo26 {
public static void main(String [] args) {
DemoC d = new DemoC();
d.print();
d.show();
d.method();
}
}
class DemoA{
public void show() {
System.out.println("DemoA");
}
}
class DemoB extends DemoA{
public void method() {
System.out.println("DemoB");
}
}
class DemoC extends DemoB{
public void print() {
System.out.println("DemoC");
}
}
输出结果
DemoC
DemoA
DemoB
继承的注意事项
子类只能继承父类所有非私有的成员(成员方法和成员变量)
子类不能继承父类的构造方法, 但是可以通过super()关键字去访问父类构造方法
不要为了部分功能而去继承
package learn_javaSe;
public class Demo27 {
public static void main(String[] args) {
// TODO Auto-generated method stub
Son s = new Son();
s.print();
}
}
/*
* a: 不同名变量
* b: 同名变量
* 在开发中是不出现子父类同名变量
* 子类继承父类就是为了使用父类成员, 如果定义了同名的成员变量就没有意义了
*/
class Father{
int num1 = 10;
int num2 = 30;
}
class Son extends Father{
int num2 = 20;
public void print() {
System.out.println(num1); // 10
System.out.println(num2); // 20 就近原则, 子类有 不用父类
}
}
输出结果
10
20
this和super的区别
-
this和super都代表什么
- this, 代表当前对象的引用, 谁来调用我, 我就代表谁
- super: 表示当前对象父类的引用
-
this和super的使用区别:
- 调用成员变量:
- this, 成员变量调用的是本类的成员变量, 也可以调用父类的成员变量
- super, 成员变量调用父类的成员变量
- 调用构造方法
- this(...) 调用本类的构造方法
- super(...) 调用父类的构造方法
- 调用成员方法
- this.成员方法 调用本类的成员方法, 也可以调用父类的成员方法
- super.成员方法 调用父类的成员方法
package learn_javaSe; public class Demo28 { public static void main(String[] args) { // TODO Auto-generated method stub Demo28_Son s1 = new Demo28_Son(); s1.print(); } } class Demo28_Father{ int num1 = 10; int num2 = 20; } class Demo28_Son extends Demo28_Father{ int num2 = 30; public void print() { System.out.println(num1); System.out.println(num2); System.out.println(super.num2); } }
输出结果
10 30 20
- 调用成员变量:
-
子类中多有的构造方法默认都会访问父类中空参构造方法
- 因为子类会继承成父类中的数据, 可能还会使用父类的数据
- 所以, 子类初始化之前, 一定要完成父类数据的初始化
-
每个构造方法的第一句默认都是: super() Object类最顶端的父类
package learn_javaSe;
public class Demo29 {
public static void main(String[] args) {
// TODO Auto-generated method stub
Demo29_Son s1 = new Demo29_Son();
}
}
class Demo29_Father{
public Demo29_Father() {
super(); // 默认添加super() 访问Object类, Object是最顶层的类
System.out.println("Father 的构造方法!");
}
}
class Demo29_Son extends Demo29_Father{
public Demo29_Son() {
super(); // 系统默认添加 super(), 用来访问父类中的空参构造
System.out.println("Son的构造方法!");
}
}
输出结果
Father 的构造方法!
Son的构造方法!
- 父类中没有无参构造怎么办
package learn_javaSe;
public class Demo30 {
public static void main(String[] args) {
// TODO Auto-generated method stub
Demo30_Son s1 = new Demo30_Son();
System.out.println(s1.getName() + " " + s1.getAge());
System.out.println("----------------------");
Demo30_Son s2 = new Demo30_Son("Mephisto",25);
System.out.println(s2.getName() + " " + s2.getAge());
}
}
class Demo30_Father{
private String name;
private int age;
/*
public Demo30_Father() {
// super();
System.out.println("Father空参构造");
}
*/
public Demo30_Father(String name, int age) {
// super();
this.name = name;
this.age = age;
System.out.println("Father有参构造");
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setAge(int age) {
this.age = age;
}
public int getAge() {
return age;
}
}
class Demo30_Son extends Demo30_Father{
public Demo30_Son() {
// super("Vincent",18); // 调用父类中的构造方法
this("Vincent",18); // 调用本类中的构造方法, 即访问 public Demo30_Son(String name, int age){}
System.out.println("Son空参构造");
}
public Demo30_Son(String name, int age) {
super(name,age);
System.out.println("Son有参构造");
}
}
输出结果
Father有参构造
Son有参构造
Son空参构造
Vincent 18
----------------------
Father有参构造
Son有参构造
Mephisto 25
package learn_javaSe;
public class Demo31 {
public static void main(String[] args) {
Zi zi = new Zi();
zi.show();
}
}
class Fu{
public int num = 10;
public Fu() {
System.out.println("Fu");
}
}
class Zi extends Fu{
public int num = 20;
public Zi() {
System.out.println("Zi");
}
public void show() {
int num = 30;
System.out.println(num);
System.out.println(this.num);
System.out.println(super.num);
}
}
输出结果
Fu
Zi
30
20
10
package learn_javaSe;
public class Demo32 {
public static void main(String[] args) {
// TODO Auto-generated method stub
Demo32_Zi zi = new Demo32_Zi();
}
/*
* 1. JVM 调用了main方法, main进栈
* 2. 遇到 Demo32_Zi zi = new Demo32_Zi(); 会先将Demo32_Fu 和 Demo32_Zi加载进内存, 在创建对象
* 同时父类和子类的静态代码块也会加载进内存 第一个输出时 Fu静态代码块, 第二个输出 Zi静态代码块
* 3. 走Demo32_Zi类的构造方法, 因为java中是分层初是化的, 先初始化父类, 然后在初始化父类,
* 所以先走父类的构造,但是在执行父类构造时, 发现父类构造代码块, 构造代码块是优先于构造方法执行的
* 所以第三个输出 Fu构造代码块 第四个输出 Fu构造方法
* 4. Demo32_Fu类加载完毕, 加载Demo32_Zi 第五个输出 Zi构造代码块 , 第六个输出 Zi构造方法
*/
}
class Demo32_Fu{
static {
System.out.println("Fu静态代码块");
}
{
System.out.println("Fu构造代码块");
}
public Demo32_Fu() {
System.out.println("Fu构造方法");
}
}
class Demo32_Zi extends Demo32_Fu{
static {
System.out.println("Zi静态代码块");
}
{
System.out.println("Zi构造代码块");
}
public Demo32_Zi() {
System.out.println("Zi构造方法");
}
}
输出结果
Fu静态代码块
Zi静态代码块
Fu构造代码块
Fu构造方法
Zi构造代码块
Zi构造方法
package learn_javaSe;
public class Demo33 {
public static void main(String[] args) {
// TODO Auto-generated method stub
Demo33_Zi z1 = new Demo33_Zi();
z1.print();
z1.method();
}
}
/*
* 不同名方法
* 同名方法
*/
class Demo33_Fu{
public void print() {
System.out.println("Fu print");
}
}
class Demo33_Zi extends Demo33_Fu{
public void method() {
System.out.println("Zi method");
}
public void print() { // 重写
super.print(); // super可以调用父类的成员方法
System.out.println("Zi print");
}
}
输出结果
Fu print
Zi print
Zi method
方法重写
重写: 子父类出现了一模一样的方法(返回值可以时子父类)
当子类需要父类一个功能,而功能主体子类有自己特有的内容时,可以重写父类中的方法, 这样, 即沿袭了父类的功能, 有定义了子类特有的内容
package learn_javaSe;
public class Demo34 {
public static void main(String[] args) {
NewPhone p1 = new NewPhone();
p1.siri();
p1.call();
p1.show();
}
}
class Demo34_Phone{
public void call() {
System.out.println("打电话!");
}
public void siri() {
System.out.println("Speak English!");
}
public static void show(){
System.out.println("Fu static show");
}
}
class NewPhone extends Demo34_Phone{
public void siri() {
super.siri();
System.out.println("说中文");
}
public static void show() { // 静态只能覆盖静态, **看多态
System.out.println("Zi static show");
}
}
输出结果
Speak English!
说中文
打电话!
Zi static show
- 方法重写注意事项
- 父类中私有方法不能被重写
- 因为父类私有方法子类根本无法继承
- 子类重写父类时,访问权限不能更低
- 最好一致
- 父类静态方法,子类也必须通过静态方法进行重写
- 静态只能被覆盖
- 子类重写父类的时候,最好声明一模一样
- 父类中私有方法不能被重写
- Override(方法重写)和overload(方法重载)区别
- Overload可以改变返回值类型, 只看参数列表
- 方法重写: 子类中出现和父类中方法声明一模一样的方法, 与返回值类型有关, 返回值是一致(或子父类)的
- 方法重载: 本类中出现和方法名一样, 参数列表不同的方法, 与返回值类型无关
- 子类调用对象的时候:
- 先找子类本身, 再找父类
final
- final修饰特点
- 修饰类, 类不能被继承
- 修饰变量变量就成了常量, 只能被赋值一次
- 修饰方法, 方法不能被重写
package learn_javaSe;
public class Demo37 {
public static void main(String[] args) {
// TODO Auto-generated method stub
Test37 t1 = new Test37();
t1.print();
double t2 = Test37.PI; // 访问常量
System.out.println(t2);
}
}
class Demo37_Father{
public final void print() {
System.out.println("访问底层数据资源");
}
}
/*
class Demo37_Son extends Demo37_Father{
public void print() {
System.out.println("哈哈,功能被我干掉了");
}
}
*/
class Test37{
final int NUM = 10; // 常量命名规范, 如果是一个单词, 所有字母大写,如果是多个中间用下划线隔开
public static final double PI = 3.14; // final 修饰变量被称为常量, 一般跟public static 更好的访问该常量
public void print() {
// num = 20;
System.out.println(NUM);
}
}
输出结果
10
3.14
- 基本数据类型, 是之不能被改变的
- 引用数据类型, 是地址值不能被改变的, 对象中的属性可以改变
package learn_javaSe;
public class Demo38 {
public static void main(String[] args) {
final int NUM = 10;
// NUM = 20;
System.out.println(NUM);
final Demo38_Person p1 = new Demo38_Person("张三",18);
// p1 = new Demo38_Person("Vincent",19);
p1.setName("Vincent");
p1.setAge(19);
System.out.println(p1.getName() + " " + p1.getAge());
method(10);
method(20);
}
public static void method(final int X) {
System.out.println(X);
}
}
class Demo38_Person{
private String name;
private int age;
public Demo38_Person() {
}
public Demo38_Person(String name, int age) {
this.name = name;
this.age = age;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setAge(int age) {
this.age = age;
}
public int getAge() {
return age;
}
}
输出结果
10
Vincent 19
10
20
- final修饰变量的初始化时
- 显示初是化
- 在对象构造完毕前即可
package learn_javaSe;
public class Demo39 {
public static void main(String[] args) {
// TODO Auto-generated method stub
Test39 t1 = new Test39();
t1.print();
}
}
class Test39{
final int num1 = 10; // 显式初始化值
// final int num2; // 成员变量默认初是化值是无效值
final int num3;
public Test39() {
num3 = 20; // 在对象构造完成之前进行常量初始化
}
public void print() {
System.out.println(num1);
System.out.println(num3);
}
}
多态
- 事物存在的多种形态
- 多态前提
- 要有继承关系
- 要有方法重写
- 要有父类引用指向子类对象
public class Demo40 {
public static void main(String[] args) {
Demo40_Cat c = new Demo40_Cat();
c.eat();
Demo40_Animal a = new Demo40_Cat();
a.eat();
}
}
class Demo40_Animal{
public void eat() {
System.out.println("动物吃饭");
}
}
class Demo40_Cat extends Demo40_Animal{
public void eat() {
System.out.println("猫吃鱼");
}
}
-
多态中的成员访问特点
- 成员变量
- 编译看左边(父类), 运行看左边(父类)
- 成员方法
- 编译看左边(父类),运行看右边(子类) (动态绑定)
- 静态方法
- 编译看左边(父类), 运行看左边(父类)
只有非静态成员方法, 编译看父类, 运行看子类
- 成员变量
package learn_javaSe;
public class Demo41 {
public static void main(String[] args) {
Demo41_Father t = new Demo41_Son(); // 父类引用指向子类对象
System.out.println(t.num);
t.print();
t.method(); // 相当于Demo41_Father.method()
Demo41_Son s = new Demo41_Son();
System.out.println(s.num);
s.print();
s.method();
}
}
class Demo41_Father{
int num = 10;
public void print() {
System.out.println("father");
}
public static void method() {
System.out.println("static father");
}
}
class Demo41_Son extends Demo41_Father{
int num = 20;
public void print() {
System.out.println("son");
}
public static void method() {
System.out.println("static son");
}
}
- 多态中向下转型和向上转型
Person p = new SuperMan(); 向上转型
SuperMan sm = (SuperMan)p; 向下转型
package learn_javaSe;
public class Demo42 {
public static void main(String[] args) {
Demo42_Person person = new Demo42_Superman(); // 父类引用指向子类对象, 超人提升为了人
person.谈生意(); // 父类引用指向子类对象就是向上转换
// person.fly();
Demo42_Superman superman = (Demo42_Superman) person;
superman.fly(); // 向下转型
/*
* 基本数据类型自动类型提升和强制转换
*/
int i = 10;
byte b = 20;
i = b; // 自动类型提升
b = (byte)i; // 强制类型转换
}
}
class Demo42_Person{
String name = "John";
public void 谈生意() {
System.out.println("谈生意");
}
}
class Demo42_Superman extends Demo42_Person{
String name = "Superman";
public void 谈生意() {
System.out.println("谈几个亿的大单子");
}
public void fly() {
System.out.println("会飞");
}
}
-
多态的好处
-
提高代码的维护性(由继承保证)
-
提高代码的扩展性(由多态保证)
- 可以当作形式参数, 接受任意子类对象
package learn_javaSe; public class Demo43 { public static void main(String[] args) { // Demo43_Cat c1 = new Demo43_Cat(); // c1.eat(); method(new Demo43_Cat()); method(new Demo43_Dog()); // Animal a = new Dog(); // 开发的时候很少在创建对象的时候用父类引用指向子类对象 // 直接创建子类对象更方便,可以使用子类中的特有属性和行为 } /* public static void method(Demo43_Cat c) { c.eat(); } public static void method(Demo43_Dog d) { d.eat(); } */ public static void method(Demo43_Animal a) { // 当作参数的时候,用多态最好, 因为扩展性强 // a.eat(); // a.lookHome(); // 不能体现子类中特有的属性和行为 // 关键字 instaceof 判断前边的引用是否是后边的数据类型 if (a instanceof Demo43_Cat) { ((Demo43_Cat)a).eat(); ((Demo43_Cat) a).catchMouse(); }else if (a instanceof Demo43_Dog) { ((Demo43_Dog)a).eat(); ((Demo43_Dog)a).lookHome(); }else { a.eat(); } } } class Demo43_Animal{ public void eat() { System.out.println("动物吃饭"); } } class Demo43_Cat extends Demo43_Animal{ public void eat() { System.out.println("猫吃鱼"); } public void catchMouse() { System.out.println("抓老鼠"); } } class Demo43_Dog extends Demo43_Animal{ public void eat() { System.out.println("狗吃肉"); } public void lookHome() { System.out.println("看家"); } }
-
-
多态弊端
- 不能使用子类的特有的属性和行为
package learn_javaSe;
public class Demo44 {
public static void main(String[] args) {
Demo44_Fu fu = new Demo44_Zi();
// fu.method();
fu.show();
}
}
class Demo44_Fu{
public void show() {
System.out.println("fu show");
}
}
class Demo44_Zi extends Demo44_Fu{
/*
public void show() {
System.out.println("zi show");
}
*/
public void method() {
System.out.println("zi method");
}
}
输出结果
fu show
抽象类的概述及其特点
-
抽象就是看不懂
-
抽象类的特点
- 抽象类和抽象方法必须用abstract关键词修饰
- abstract class 类名{}
- public abstract void demo();
- 抽象类不一定由抽象方法, 有抽象方法的类一定是抽象类或者是接口
- 抽象类不能实例化
- 按照多态的方式, 由具体的子类实例化, 其实这也是多态的一种, 抽象类多态
- 抽象类的子类
- 要么是抽象类
- 要么重写抽象类中的所有抽象方
- 抽象类和抽象方法必须用abstract关键词修饰
-
抽象类成员特点
- 成员变量,既可以是变量,也可以是常量, abstract不能修饰成员变量
- 有构造方法, 用于子类访问父类数据的初始化
- 抽象方法 强制要求子类做的事情
- 非抽象方法 子类继承的事情, 提高代码复用性
package learnjava;
/**
* @author Mephisto
* @version 2018年7月27日 上午10:40:46
*/
public class Demo3 {
public static void main(String[] args) {
Yue yue = new Yue();
yue.ziG();
}
}
abstract class AbstractKui{
public void ziG() {
System.out.println("用牙签");
}
}
class Yue extends AbstractDemo{
public void ziG() {
System.out.println("用指甲刀");
}
}
class Lin extends AbstractDemo{
public void ziG() {
System.out.println("用锤子");
}
}
一个抽象类如果没有抽象方法, 可以有抽象类, 这么做的目的只有一个,就是不让其他类创建本类对象,交给子类完成
abstract不能和那些关键字共存?
- abstract 和static
- 被abstract修饰的方法没有方法体
- 被static修饰的可以用类名.调用,但是类名.抽象方法是没有意义的
- abstract 和 final
- 被abstract修饰的方法强制子类重写
- 被final修饰的不让子类重写,所以他俩矛盾
- abstract和private
- 被abstract修饰的是为了让子类看到并强制重写
- 被private修饰不让子类访问,所以他俩是矛盾的
接口
从狭义的角度, java中的interface
从广义的角度, 对外提供规则的都是接口
- 特点
- 关键词interface
- interface 接口名 {}
- 类实现接口用implements表示
- class 类名 implements 接口名 {}
- 接口不能实现实例化
- 按照多态的方式来实例化
- 接口的子类
- 可以是抽象类, 但是意义不大
- 可以是具体类, 要重写接口中的所有抽象方法(推荐方案)
- 关键词interface
package learnjava;
/**
* @author Mephisto
* @version 2018年7月27日 下午2:28:48
*/
public class Demo8 {
public static void main(String[] args) {
// Demo8Inter name = new // Demo8Inter(); // 接口不能被实例化, 因为调用抽象方法没有意义
Demo8Inter inter = new Demo8Test(); // 父类引用指向子类对象
inter.print();
}
}
interface Demo8Inter{
/**
* print
*/
public abstract void print(); //接口中的方法都是抽象的
}
class Demo8Test implements Demo8Inter{
@Override
public void print() {
System.out.println("这是类实现接口");
}
}
- 接口成员变量
- 这能是常量, 并且是静态的并且是公共的
- 默认修饰符 public static final
- 接口是没有构造方法的 一个类如果不写继承任何类,默认继承Object类
- 接口成员方法 只能是抽象的 默认修饰符 public abstract
类与类, 类与接口, 接口与接口
- 类与类
- 继承关系, 只能单继承, 可以多层继承
- 类与接口
- 实现关系, 可以单实现, 也可以多实现
- 并且还可以在继承一个类的同时实现多个接口
- 接口与接口
- 继承关系, 可以单继承, 也可以多层继承
package learnjava;
/**
* @author Mephisto
* @version 2018年7月27日 下午2:45:41
*/
public class Demo10 {
public static void main(String[] args) {
Demo10Test test = new Demo10Test();
test.printA();
test.printB();
}
}
interface Demo10InterA{
/**
* printA
*/
void printA();
}
interface Demo10InterB{
/**
* printB
*/
void printB();
}
interface Demo10InterC extends Demo10InterA,Demo10InterB{
}
class Demo10Test extends Object implements Demo10InterA,Demo10InterB{
@Override
public void printA() {
System.out.println("printA");
}
@Override
public void printB() {
System.out.println("printB");
}
}
抽象类和接口的区别
- 成员区别
- 抽象类:
- 成员变量: 可以变量, 也可以常量
- 构造方法: 有
- 成员方法: 可以抽象, 也可以非抽象
- 接口:
- 成员变量: 只可以常量
- 成员方法: 只可以抽象
- 抽象类:
- 关系区别
- 类与类
- 继承, 单继承
- 类与接口
- 实现, 单实现, 多实现
- 接口与接口
- 继承, 单继承, 多继承
- 类与类
- 设计理念区别
- 抽象类 被继承体现的是 : "is a" 的关系, 抽象类中定义的是该继承体系中的共性功能
- 接口 被实现体现的是:"like a" 的关系, 接口中定义的是该继承体系的扩展功能
package关键字
将字节码(.class)进行分类存放
包其实就是文件夹
域名倒写 com.xxxx.功能名(或模块名)
- 分类
- 按照功能划分
- 按照模块划分
- 定义包的格式
- package 包名
- 多级包用
.
分开
- 定义包的注意事项
- package语句必须是程序的第一条可执行的代码
- package语句在一个java文件中只能有一个
- 如果没有package, 默认表示无包名
import关键字
- import其实就是让有包的类对调用者可见,不用写全类名
- package import class
四种权限修饰符
修饰符 | 本类 | 同一个包下(子类和无关类) | 不同包下(子类) | 不同包下(无关类) |
---|---|---|---|---|
private | Y | |||
默认 | Y | Y | ||
protected | Y | Y | Y | |
public | Y | Y | Y | Y |
- protected 关键字是只有这个类的子类可以访问
- default即不写修饰符, 那就只有子类, 跟同一个包的类可以访问
- private只有类本身可以访问
- public 所有类都能访问
类及其组成所使用的常见修饰符
- 修饰符
- 权限修饰符:private , default, protected, public
- 状态修饰符:static , final
- 抽象修饰符:abstract
- 类
- 权限修饰符:default,public
- 状态修饰符:final
- 抽象修饰符:abstract
- 用的最多的public
- 成员变量
- 权限修饰符: private default protected public
- 状态修饰符: static final
- 用的最多的private
- 构造方法
- 权限修饰符: private default protected public
- 用的最多的 public
- 成员方法
- 权限修饰符 private default protected public
- 状态修饰符 static final
- 用的最多的 public
- 除此以外的组合规则
- 成员变量 public static final
- 成员方法 public static
内部类
- 特点
- 内部可以直接访问外部类的成员, 包括私有
- 外部类需要访问内部类的成员必须创建对象
外部类名.内部类名 对象名 = 外部类对象.内部类对象;
package learnjava;
/**
* @author Mephisto
* @version 2018年7月28日 上午11:01:25
*/
public class Demo12 {
public static void main(String[] args) {
/** 创建内部类对象 */
Outer12.Inner12 inner = new Outer12().new Inner12();
inner.method();
}
}
class Outer12{
private int num = 10;
class Inner12{
public void method() {
System.out.println(num);
}
}
}
package learnjava;
/**
* @author Mephisto
* @version 2018年7月28日 上午11:01:25
*/
public class Demo12 {
public static void main(String[] args) {
/* 创建内部类对象 */
// Outer12.Inner12 inner = new Outer12().new Inner12();
// inner.method();
Outer12 outer12 = new Outer12();
outer12.print();
}
}
class Outer12{
private int num = 10;
/* 成员方法被私有 */
private class Inner12{
public void method() {
System.out.println(num);
}
}
public void print() {
Inner12 inner12 = new Inner12();
inner12.method();
}
}
package learnjava;
/**
* @author Mephisto
* @version 2018年7月28日 上午11:12:08
*/
public class Demo13 {
public static void main(String[] args) {
/** 外部类名.内部类名 对象名 = 外部类名.内部类对象; */
Outer13.Inner oInner = new Outer13.Inner();
oInner.method();
Outer13.Inner2.print();
}
}
class Outer13 {
static class Inner{
public void method() {
System.out.println("method");
}
}
static class Inner2{
public static void print() {
System.out.println("print");
}
}
}
package learnjava;
import java.io.IOError;
/**
* @author Mephisto
* @version 2018年7月28日 上午11:19:42
*/
public class Demo14 {
public static void main(String[] args) {
Outer14.Inner14 oi = new Outer14().new Inner14();
oi.show();
}
}
class Outer14{
public int num = 10;
class Inner14{
public int num = 20;
public void show() {
int num = 30;
/** 要求: 使用已知的变量,在控制台输出10,20,30 */
/*
* 内部类之所以能够获取到外部类的成员, 是因为他能获取到外部类的引用外部类名.this
*/
System.out.println(Outer14.this.num);
System.out.println(this.num);
System.out.println(num);;
}
}
}
局部内部类访问局部变量的问题
- 局部内部类访问局部变量必须使用final修饰
- 局部内部类在访问他所在的方法中的局部变量必须使用final修饰
- 因为当调用这个方法时,局部变量如果没有用final修饰,他的生命周期和方法的生命周期是一样的,当方法弹栈,这个局部变量也会消失,那么如果这个局部内部类对象还没有马上消失享用这个局部变量,就没有了,如果final修饰会在类加载的时候进入变量池,即使方法弹栈,常量池的常量还在,也可以继续使用
- 在jdk1.8取消了这件事
匿名内部类
-
就是内部类的简化写法
-
前提: 存在一个类或接口(这里的类可以事具体类也可以是抽象类
-
格式:
new 类名或者接口名(){ 重写方法; }
-
本质
- 是一个继承类该类或者实现了该接口的子类匿名对象
package learnjava;
/**
* @author Mephisto
* @version 2018年7月28日 上午11:44:12
*/
public class Demo16 {
public static void main(String[] args) {
Outer16 o = new Outer16();
o.method();
}
}
interface Inter16{
/**
* print
*/
abstract void print();
}
class Outer16 {
/*
class Inner16 implements Inter16{
@Override
public void print() {
System.out.println("print");
}
}
*/
public void method(){
/**
Inner16 inner16 = new Inner16();
inner16.print();
*/
new Inter16() { // 实现Inter16 接口
@Override // 重写方法
public void print() {
System.out.println("Hello world!");
}
}.print();
}
}
package learnjava;
/**
* @author Mephisto
* @version 2018年7月28日 上午11:58:53
*/
public class Demo18 {
public static void main(String[] args) {
Outer18 o = new Outer18();
o.method();
}
}
interface Inter18{
public abstract void show1();
public abstract void show2();
}
/** 匿名内部类只针对重写一个方法时候使用 */
class Outer18{
public void method(){
/**
new Inter18() {
@Override
public void show2() {
System.out.println("show2");
}
@Override
public void show1() {
System.out.println("show1");
}
}.show1();
new Inter18() {
@Override
public void show2() {
System.out.println("show2");
}
@Override
public void show1() {
System.out.println("show1");
}
}.show2();
*/
Inter18 i = new Inter18() {
@Override
public void show2() {
System.out.println("show2");
}
@Override
public void show1() {
System.out.println("show2");
}
/*
public void show3() {
System.out.println("show3");
}
*/
};
i.show1();
i.show2();
// i.show3(); // 匿名内部类不能向下强转, 因为没有子类类名
}
}