补
补充之前的知识点:
==和equals方法
- “==”代表比较双方是否相同。如果是基本类型则表示值相等,如果是引用类型则表示地址相等即是同一个对象。
- equals() 提供定义“对象内容相等”的逻辑。比如,我们在公安系统中认为 id 相同的人就是同一个人、学籍系统中认为学号相同的人就是同一个人。
- equals()默认是比较两个对象的 hashcode。但,可以根据自己的要求重写 equals 方法。
自定义类重写 equals()方法
public class TestEquals {
public static void main(String[ ] args) {
Person p1 = new Person(123,"秃头");
Person p2 = new Person(123,"小孙");
System.out.println(p1==p2); //false,不是同一个对象
System.out.println(p1.equals(p2)); //true,id相同则认为两个对象内容相同
String s1 = new String("老秃头");
String s2 = new String("老秃头");
System.out.println(s1==s2); //false, 两个字符串不是同一个对象
System.out.println(s1.equals(s2)); //true, 两个字符串内容相同
}
}
class Person {
int id;
String name;
public Person(int id,String name) {
this.id=id;
this.name=name;
}
public boolean equals(Object obj) {
if(obj == null){
return false;
}else {
if(obj instanceof Person) {
Person c = (Person)obj;
if(c.id==this.id) {
return true;
}
}
}
return false;
}
}
super关键字
- super“可以看做”是直接父类对象的引用。可通过 super 来访问父类中被子类覆盖的方法或属性。
- 使用 super 调用普通方法,语句没有位置限制,可以在子类中随便调用。
- 在一个类中,若是构造方法的第一行没有调用 super(...)或者 this(...); 那么 Java 默认都会调用 super(),含义是调用父类的无参数构造方法。
super 关键字的使用
public class TestSuper01 {
public static void main(String[ ] args) {
new ChildClass().f();
}
}
class FatherClass {
public int value;
public void f(){
value = 100;
System.out.println ("FatherClass.value="+value);
}
}
class ChildClass extends FatherClass {
public int value;
public int age;
public void f() {
super.f(); //调用父类的普通方法
value = 200;
System.out.println("ChildClass.value="+value);
System.out.println(value);
System.out.println(super.value); //调用父类的成员变量
}
public void f2() {
System.out.println(age); }
}
封装
封装的作用和含义
- 提高代码的安全性。
- 提高代码的复用性。
- “高内聚”:封装细节,便于修改内部代码,提高可维护性。
- “低耦合”:简化外部调用,便于调用者使用,便于扩展和协作。
封装的实现-使用访问控制符
- 若父类和子类在同一个包中,子类可访问父类的 protected 成员,也可访问父类对象的protected 成员。
- 若子类和父类不在同一个包中,子类可访问父类的 protected 成员,不能访问父类对象的 protected 成员。
封装的使用细节
- 属性一般使用 private 访问权限。
- 属性私有后, 提供相应的 get/set 方法来访问相关属性,这些方法通常是public 修饰的,以提供对属性的赋值与读取操作(注意:boolean 变量的 get方法是 is 开头!)。
- 方法:一些只用于本类的辅助性方法可以用 private 修饰,希望其他类调用的方法用 public 修饰。
JavaBean 的封装演示:
public class Person {
// 属性一般使用 private 修饰
private String name;
private int age;
private boolean flag;
// 为属性提供 public 修饰的 set/get 方法
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public boolean isFlag() {// 注意:boolean 类型的属性 get 方法是 is 开头的
return flag;
}
public void setFlag(boolean flag) {
this.flag = flag;
}
}
封装的使用:
class Person {
private String name;
private int age;
public Person() {
}
public Person(String name, int age) {
this.name = name;
// this.age = age;//构造方法中不能直接赋值,应该调用 setAge 方法
setAge(age);
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setAge(int age) {
//在赋值之前先判断年龄是否合法
if (age > 130 || age < 0) {
this.age = 18;//不合法赋默认值 18
} else {
this.age = age;//合法才能赋值给属性 age
}
}
public int getAge() {
return age;
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + "]";
}
}
public class Test2 {
public static void main(String[ ] args) {
Person p1 = new Person();
//p1.name = "小红"; //编译错误
//p1.age = -45; //编译错误
p1.setName("小红");
p1.setAge(-45);
System.out.println(p1);
Person p2 = new Person("小白", 300);
System.out.println(p2);
}
}
多态
- 多态是方法的多态,不是属性的多态(多态与属性无关)。
- 多态的存在要有 3 个必要条件:继承,方法重写,父类引用指向子类对象。
- 父类引用指向子类对象后,用该父类引用调用子类重写的方法,此时多态就出现了。
多态和类型转换:
class Animal {
public void shout() {
System.out.println("叫了一声!");
}
}
class Dog extends Animal {
public void shout() {
System.out.println("旺旺旺!");
}
public void seeDoor() {
System.out.println("看门中....");
}
}
class Cat extends Animal {
public void shout() {
System.out.println("喵喵喵喵!");
}
}
public class TestPolym {
public static void main(String[ ] args) {
Animal a1 = new Cat(); // 向上可以自动转型
//传的具体是哪一个类就调用哪一个类的方法。大大提高了程序的可扩展性。
animalCry(a1);
Animal a2 = new Dog();
animalCry(a2);//a2 为编译类型,Dog 对象才是运行时类型。
/*编写程序时,如果想调用运行时类型的方法,只能进行强制类型转换。
* 否则通不过编译器的检查。*/
Dog dog = (Dog)a2;//向下需要强制类型转换
dog.seeDoor();
}
// 有了多态,只需要让增加的这个类继承 Animal 类就可以了。
static void animalCry(Animal a) {
a.shout();
}
/* 如果没有多态,我们这里需要写很多重载的方法。
* 每增加一种动物,就需要重载一种动物的喊叫方法。非常麻烦。
static void animalCry(Dog d) {
d.shout();
}
static void animalCry(Cat c) {
c.shout();
}*/
}
结果:
喵喵喵喵!
汪汪汪!
看门中。。。
对象的转型
- 父类引用指向子类对象,我们称这个过程为向上转型,属于自动类型转换。
- 向上转型后的父类引用变量只能调用它编译类型的方法,不能调用它运行时类型的方法。这时,我们就需要进行类型的强制转换,我们称之为向下转型。
public class TestCasting {
public static void main(String[ ] args) {
Object obj = new String("秃头小子"); // 向上可以自动转型
// obj.charAt(0) 无法调用。编译器认为 obj 是 Object 类型而不是 String 类型
/* 编写程序时,如果想调用运行时类型的方法,只能进行强制类型转换。
* 不然通不过编译器的检查。 */
String str = (String) obj; // 向下转型
System.out.println(str.charAt(0)); // 位于 0 索引位置的字符
System.out.println(obj == str); // true.他们俩运行时是同一个对象
}
}
结果:
秃
true
public class TestCasting2 {
public static void main(String[ ] args) {
Object obj = new String("秃头小子");
//真实的子类类型是 String,但是此处向下转型为 StringBuffer
StringBuffer str = (StringBuffer) obj;
System.out.println(str.charAt(0));
}
}
结果:报异常
public class TestCasting3 {
public static void main(String[ ] args) {
Object obj = new String("秃头小子");
if(obj instanceof String){
String str = (String)obj;
System.out.println(str.charAt(0));
}else if(obj instanceof StringBuffer){
StringBuffer str = (StringBuffer) obj;
System.out.println(str.charAt(0));
}
}
}
抽象类
抽象方法和抽象类
- 使用 abstract 修饰的方法,没有方法体,只有声明。
- 定义的是一种“规范”,就是告诉子类必须要给抽象方法提供具体的实现。
- 包含抽象方法的类就是抽象类。
- 通过抽象类,我们就可以做到严格限制子类的设计,使子类之间更加通用。
//抽象类
abstract class Animal {
abstract public void shout(); //抽象方法
}
class Dog extends Animal {
//子类必须实现父类的抽象方法,否则编译错误
public void shout() {
System.out.println("汪汪汪!");
}
public void seeDoor(){
System.out.println("看门中....");
}
}
//测试抽象类
public class TestAbstractClass {
public static void main(String[ ] args) {
Dog a = new Dog();
a.shout();
a.seeDoor();
}
}
- 有抽象方法的类只能定义成抽象类
- 抽象类不能实例化,即不能用 new 来实例化抽象类。
- 抽象类可以包含属性、方法、构造方法。但是构造方法不能用来 new 实例,只能用来被子类调用。
- 抽象类只能用来被继承。
- 抽象方法必须被子类实现。
接口
接口的作用
如何定义和使用接口
声明格式:[访问修饰符] interface 接口名 [extends 父接口 1,父接口 2…] {常量定义;方法定义;}
- 访问修饰符:只能是 public 或默认。
- 接口名:和类名采用相同命名机制。
- extends:接口可以多继承。
- 常量:接口中的属性只能是常量,总是:public static final 修饰。不写也是。
- 方法:接口中的方法只能是:public abstract。 省略的话,也是 public abstract。
要点:
- 子类通过 implements 来实现接口中的规范。
- 接口不能创建实例,但是可用于声明引用变量类型。
- 一个类实现了接口,必须实现接口中所有的方法,并且这些方法只能是 public 的。
- JDK1.8(不含 8)之前,接口中只能包含静态常量、抽象方法,不能有普通属性、构造 方法、普通方法。
- JDK1.8(含 8)后,接口中包含普通的静态方法、默认方法。
接口的使用:
public class TestInterface {
public static void main(String[ ] args) {
Volant volant = new Angel();
volant.fly();
System.out.println(Volant.FLY_HIGHT);
Honest honest = new GoodMan();
honest.helpOther();
}
}
/**飞行接口*/
interface Volant {
int FLY_HIGHT = 100; // 总是:public static final 类型的;
void fly(); //总是:public abstract void fly();
}
/**善良接口*/
interface Honest {
void helpOther();
}
/**Angel 类实现飞行接口和善良接口*/
class Angel implements Volant, Honest{
public void fly() {
System.out.println("我是天使,飞起来啦!");
}
public void helpOther() {
System.out.println("扶老奶奶过马路!");
}
}
class GoodMan implements Honest {
public void helpOther() {
System.out.println("扶老奶奶过马路!");
}
}
class BirdMan implements Volant {
public void fly() {
System.out.println("我是鸟人,正在飞!");
}
}
结果:
我是天使,飞起来啦!
100
扶老奶奶过马路
接口的多继承
接口的多继承:
interface A {
void testa();
}
interface B {
void testb();
}
/**接口可以多继承:接口 C 继承接口 A 和 B*/
interface C extends A, B {
void testc();
}
public class Test implements C {
public void testc() {
}
public void testa() {
}
public void testb() {
}
}
秃头建议:接口语法本身非常简单,但是如何真正使用?这才是大学问。我们需要后面在项目中反复使用,大家才能体会到。 学到此处,能了解基本概念,熟悉基本语法,就是“好学生”了。 请继续努力!再请工作后,闲余时间再看看上面这段话,相信你会有更深的体会。
字符串String类详解
String:就是把一堆字符串起来,统一使用。
- String 类又称作不可变字符序列。
- String 位于 java.lang 包中,Java 程序默认导入 java.lang 包下的所有类。
- Java 字符串就是 Unicode 字符序列,例如字符串“Java”就是 4 个 Unicode 字符’J’、’a’、’v’、’a’组成的。
- Java 没有内置的字符串类型,而是在标准 Java 类库中提供了一个预定义的类String,每个用双引号括起来的字符串都是 String 类的一个实例
String 类的简单使用String e = "" ; // 空字符串String greeting = " Hello World " ;
"+"连接符int age = 18;String str = "age is" + age ; //str 赋值为"age is 18"//这种特性通常被用在输出语句中:System. out .println( "age is" + age );
String类和常量池
String g1 = "秃头小子";
String g2 = "秃头小子";
String g3 = new String("秃头小子");
System.out.println(g1 == g2); // true
System.out.println(g1 == g3); // false
System.out.println(g1.equals(g3)); //true
详细的大家可以阅读API文档
String类常用方法
String 类常用方法一:
public class StringTest1 {
public static void main(String[ ] args) {
String s1 = "core Java";
String s2 = "Core Java";
System.out.println(s1.charAt(3));//提取下标为 3 的字符
System.out.println(s2.length());//字符串的长度
System.out.println(s1.equals(s2));//比较两个字符串是否相等
System.out.println(s1.equalsIgnoreCase(s2));//比较两个字符串(忽略大小
写)
System.out.println(s1.indexOf("Java"));//字符串 s1 中是否包含 Java
System.out.println(s1.indexOf("apple"));//字符串 s1 中是否包含 apple
String s = s1.replace(' ', '&');//将 s1 中的空格替换成&
System.out.println("result is :" + s);
}
}
结果:
e
9
false
true
5
-1
result is :core&java
String 类常用方法二:
public class StringTest2 {
public static void main(String[ ] args) {
String s = "";
String s1 = "How are you?";
System.out.println(s1.startsWith("How"));//是否以 How 开头
System.out.println(s1.endsWith("you"));//是否以 you 结尾
s = s1.substring(4);//提取子字符串:从下标为 4 的开始到字符串结尾为止
System.out.println(s);
s = s1.substring(4, 7);//提取子字符串:下标[4, 7) 不包括 7
System.out.println(s);
s = s1.toLowerCase();//转小写
System.out.println(s);
s = s1.toUpperCase();//转大写
System.out.println(s);
String s2 = " How old are you!! ";
s = s2.trim();//去除字符串首尾的空格。注意:中间的空格不能去除
System.out.println(s);
System.out.println(s2);//因为 String 是不可变字符串,所以 s2 不变
}
}
结果:
true
false
are you?
are
how are you?
HOW ARE YOU?
How old are you!!
How old are you!
字符串相等的判断
- equals 方法用来检测两个字符串内容是否相等。如果字符串 s 和 t 内容相等,则s.equals(t)返回 true,否则返回 false。
- 要测试两个字符串除了大小写区别外是否是相等的,需要使用 equalsIgnoreCase方法。
- 判断字符串是否相等不要使用"=="。
忽略大小写的字符串比较:"Hello" .equalsIgnoreCase( "hellO" ); //true
public class TestStringEquals {
public static void main(String[ ] args) {
String g1 = "秃头小子";
String g2 = "秃头小子";
String g3 = new String("秃头小子");
System.out.println(g1 == g2); // true 指向同样的字符串常量对象
System.out.println(g1 == g3); // false g3 是新创建的对象
System.out.println(g1.equals(g3)); // true g1 和 g3 里面的字符串内容是一样
的
}
}
内部类
- 内部类提供了更好的封装。只能让外部类直接访问,不允许同一个包中的其他类直接访问。
- 内部类可以直接访问外部类的私有属性,内部类被当成其外部类的成员。但外部类不能访问内部类的内部属性。
注意内部类只是一个编译时概念,一旦我们编译成功,就会成为完全不同的两个类。对于一个名为 Outer 的外部类和其内部定义的名为 Inner 的内部类。编译完成后会出现 Outer.class和 Outer$Inner.class 两个类的字节码文件。所以内部类是相对独立的一种存在,其成员变量/方法名可以和外部类的相同。
内部类的定义和使用:/**外部类 Outer*/class Outer {private int age = 10;public void show(){System. out .println( age ); //10}/**内部类 Inner*/public class Inner {//内部类中可以声明与外部类同名的属性与方法private int age = 20;public void show(){System. out .println( age ); //20}}}
内部类分类
非静态内部类
- 非静态内部类对象必须寄存在一个外部类对象里。因此,如果有一个非静态内部类
- 对象那么一定存在对应的外部类对象。非静态内部类对象单独属于外部类的某个对象。
- 非静态内部类可以直接访问外部类的成员,但是外部类不能直接访问非静态内部类成员。
- 非静态内部类不能有静态方法、静态属性和静态初始化块。
- 成员变量访问要点:
- 内部类属性:this.变量名。
- 外部类属性:外部类名.this.变量名。
内部类中访问成员变量/** 外部类 Outer1*/class Outer1 {private int age = 10 ;public void show(){System. out .println( age ); //10}/** 内部类 Inner*/public class Inner1 {// 内部类中可以声明与外部类同名的属性与方法private int age = 20 ;public void show(){ System. out .println( age ); //20System. out .println(Outer1. this . age ); //10 访问外部类的普通属性}}}
内部类的访问/*** 测试非静态内部类*/public class TestInnerClass1 {public static void main(String[ ] args) {//先创建外部类实例,然后使用该外部类实例创建内部类实例Outer1.Inner1 inner = new Outer1(). new Inner1();inner.show();}}
静态内部类
定义方式:static class ClassName {//类体}
静态内部类的访问/*测试静态内部类*/ class Outer2{private int a = 10 ;private static int b = 20 ;//相当于外部类的一个静态成员static class Inner2{public void test(){// System.out.println(a); //静态内部类不能访问外部类的普通属性System. out .println( b ); // 静态内部类可以访问外部类的静态属性}}}public class TestStaticInnerClass {public static void main(String[ ] args) {//通过 new 外部类名 . 内部类名 () 来创建内部类对象Outer2.Inner2 inner = new Outer2.Inner2();inner.test();}}
匿名内部类
语法:new 父类构造器(实参类表) \实现接口 () {//匿名内部类类体!}
匿名内部类的使用:/*** 测试匿名内部类*/public class TestAnonymousInnerClass {public void test1(A a) {a.run();}public static void main(String[] args) {TestAnonymousInnerClass tac = new TestAnonymousInnerClass();tac.test1( new A() {@Overridepublic void run() {System. out .println( " 匿名内部类测试 ! 我是新定义的 第一个匿名内部类!" );}});tac.test1( new A() {@Overridepublic void run() {System. out .println( " 我是新定义的第二个匿名内部类 " );}});}}interface A {void run();}
注意:匿名内部类没有访问修饰符。匿名内部类没有构造方法。因为它连名字都没有那又何来构造方法呢。
局部内部类
方法中的内部类/*** 测试局部内部类*/public class TestLocalInnerClass {public void show() { // 作用域仅限于该方法class Inner3 {public void fun() {System. out .println( "helloworld" );}}new Inner3().fun();}public static void main(String[ ] args) {new TestLocalInnerClass().show();}}
只讲干货
#有什么错误的地方大家多多担待,欢迎大家留下意见共同努力。
#需要什么技术的内容大家也可以积极留言。
#有升本的伙伴也可留言,后序也可更新升本内容C 和数据结构。
#有需要的伙伴或有什么问题直接联留下wx或联系邮箱2821835676qq.com