第7章 Java的面向对象(上)
7.5 使用类和对象
7.5.1 创建和使用对象
单个对象的创建过程
1.将xxx.class文件中相关类信息读取道内存空间的方法区,这个过程叫做类的加载。
2.当程序开始运行时找main()方法去执行方法体中的语句,使用new来创建对象。
3.若没有执行初始值采用默认初始化,否则采用执行的数值来作为初始化
4.可以通过构造块开更改成员变量的数值
5.执行构造方法体中的语句可以再次修改成员变量的数值
6.此时对象创建完毕,继续执行后续的语句
public class TestSuperObject{
{
System.out.println("TestSuperObject类中的构造块");
}
public TestSuperObject(){
System.out.println("TestSuperObject()");
}
static{
System.out.println("TestSuperObject类中的静态语句块");
}
public static void main(String[] args){
TestSuperObject ts = new TestSuperObject();
}
}
执行结果:
TestSuperObject类中的静态语句块
TestSuperObject类中的构造块
TestSuperObject()
子类对象创建过程
1.先加载父类再加载子类,限制性父类的静态语句块,再执行子类的静态语句块;
2.执行父类的构造块,再执行父类的构造方法体,此时父类部分构造完毕;
3.执行子类的构造块,再执行子类的构造方法体,此时子类的对象构造完毕;
public class TestSubObject extends TestSuperObject{
{
System.out.println("TsetSubObject类中的构造块");//2
}
public TestSubObject(){
System.out.println("TsetSubObject()");//3
}
static{
System.out.println("TsetSubObject类中的静态语句块");//1
}
public static void main(String[] args){
TestSubObject ts = new TestSubObject();
}
}
执行结果:
TestSuperObject类中的静态语句块
TsetSubObject类中的静态语句块
TestSuperObject类中的构造块
TestSuperObject()
TsetSubObject类中的构造块
TsetSubObject()
第8章 Java的面向对象(中)
8.1 类的继承
8.1.1 父类和子类
在Java中,一个类只能有一个父类,也就是说在extends关键字前只能有一个类,它不支持多重继承
<修饰符> class <子类名> extends <父类名>
{
[<成员变量定义>]...
[<方法的定义>]...
}
8.1.2 调用父类的构造方法
一个子类可以十分简单的访问构造方法,具体格式如下:Super(参数)
8.1.3 访问父类的属性和方法
子类访问父类中的属性和方法:Super.[方法和全局变量];
8.1.4 多重次继承
类B继承了类A,类C继承了类B
8.1.5 重写父类的方法
public class feiniao
{
public void fly(){ ... }
}
public class tuoniao extends feiniao
{
public void fly(){ ... }//重写了父类的方法
public void callOverrideMethod()
{
super.fly;//子类通过这种方式调用父类的方法
}
}
8.2 重写和重载
8.2.1 重写
重写实际上就是重写子类,重新编写父类方法以达到自己的需要
public class chongxie
{
void print(){...}
}
class Chongxieone extends chongxie
{
void print(){...}//子类重写了父类的方法
}
Java重写的规则
①父类中的方法并不是在任何情况下都能够重写的,当父类中的方法控制修饰符为private时,该方法只能够被自己的类访问,不能够被外部的类访问,因此子类是不能够重写的;
②如果定义父类的方法问public,子类中绝对不能够定义为private;
8.2.2 重载
在Java程序中,同一类中可以有两个或者多个方法具有相同的方法名,只要它们的参数不同即可,这就是方法的重载
public class Czai{
String ename;
int age;
void print(){...}
void print(String a,int b){...}
void print(String a,int b,int c,int d){...}
void print(String a,int b,int c,double d){...}
}
class textdir{
public static void main(String args[])
{
Czai a1 = new Czai();
a1.ename="...";
a1.age=28;
a1.print();
a1.print("...",27);
a1.print("...",1,1,1);
a1.print("...",1,1,1.0);
}
}
第9章 Java的面向对象(下)
9.2 多态
9.2.1 何谓多态
基本概念
多态就是指同一种事物表现出来的多种形态,如:饮料有可乐,雪碧,红牛,美年达等等,而在程序中则有不同类型的数据,比如整数:byte b = 10;short s=10,int i=10;
C++中多态分为两种:编译多态、运行多态
Java中的多态只有一种,就是运行时多态,是一种运行期间的行为,而不是编译期间的行为。
语法格式
父类类型 引用 = new 子类类型();
如:
Person p = new Student();
p.show();
解析:在编译阶段p是Person类型,因此调用Person类自己的show()方法,若是没有则编译时报错
在运行阶段p真正指向的对象是Student,因此最终调用的是Student类中自己的show方法
当使用多态方式调用方法的时候,首先会检查父类中是否有该方法,如果没有则编译报错
如果有,再去调用子类的同名方法。(此处注意:静态static方法属于特殊情况,静态方法只能继承,不能重写override,如果子类中定义了同名同形式的静态方法,它对父类方法只能起到隐藏的作用。调用的时候用谁的引用则调用谁的版本)
多态存在的三个必要条件:
1.要有继承
2.要有重写
3.父类引用指向子类对象
案例:自定义Person类实现封装,特征有年龄和姓名,自定义Student类继承自Person类实现封装,特征有:学号。自定义TestPersonStudent类,在main()方法中使用Person类的引用,指向Student类的对象
多态的效果
1.对于指向子类对象的父类来说,在编译期间只能调用父类的方法,不能直接调用子类的犯法。
2.对于父子类都有的非静态方法来说,最终调用子类中的重写版本。
3.对于父子类中都有的静态方法来说,最终调用父类中的版本,与指向的对象类型无关
引用类型之间的转换
基本概述
9.2.2 演示Java中的多态
public class Person {
//自定义Person类并且封装
private String name;//姓名
private int age;//年龄
//有参无参构造进行封装
//Alt+S Generate Constructor using Filed...生成无参构造
public Person() {super();}
//Alt+S Generate Constructor From SuperClass 生成有参构造
public Person(String name, int age) {super();this.name = name;this.age = age;}
//Alt+s Generate Getter and Setter全选,ok生成get、set方法以及有参无参构造等......
public String getName() {return name;}
public void setName(String name) {this.name = name;}
public int getAge() {return age;}
public void setAge(int age) {
if(age>0 && age<120){this.age = age;}
else{System.out.println("年龄不合理");}}
public void show(){System.out.println("我是"+getName()+",今年"+getAge()+"岁了!");}
public static void test(){System.out.println("Person类的静态方法");}}
//自定义Student类实现封装,Student继承自Person类,是其子类
public class Student extends Person{private int id;//学号
//生成Get和Set方法
public int getId() {return id;}
public void setId(int id) {this.id = id;}
//生成有参无参构造
public Student(int id) {if(id >0){this.id=id;}else{System.out.println("学号不合理");}}
public Student() {super();}
public Student(String name, int age, int id) {super(name, age);setId(id);}
@Override
//重写父类的show方法
public void show(){super.show();System.out.println("字号:"+getId());}}
// @Override 报错,因为静态方法不能够被重写
// public static void test(){System.out.println("Student类中的静态方法");}
public class TestPersonStudent {
public static void main(String[] args){
//使用父类的引用指向父类自己的对象
Person p = new Person();
//调用父类自己的show()方法
p.show();
System.out.println("----------------------");
//使用子类的引用指向子类自己的对象
Student s = new Student();
//当子类中没有show方法的时候,则调用父类Person中的show方法
//当子类重写show方法后,则调用子类student自己的show方法
s.show();
System.out.println("------------------------");
//使用父类的引用指向之类的对象形成多态
//发生student类型向Person类的转换,小范围向大范围的转换,自动类型转换
Person ps = new Student("zhangsan",18,1010);
//思考:ps调用的show()放大到底是Person类的还是Student类的
//在编译期间调用的是Person类的show(),在运行阶段调用的是Student的show方法
ps.show();
System.out.println("------------------------");
//使用ps调用非静态的方法进行测试
//ps是Person类型的引用,因此可以调用Person类自己的方法
String str = ps.getName();
System.out.println("获取到的姓名是:"+str);
// ps.getId();父类不能调用子类的方法
System.out.println("-------------------------");
//使用ps调用静态方法进行测试,静态的成员推荐使用类名.的方式
// ps.test();//黄线代表警告
Person.test();
System.out.println("-------------------------");
//如何实现子类方法中的调用?
//Person类型向Student类型进行转化,大=>小,需要强制类型转换
Student st = (Student) ps;
int rs = st.getId();
System.out.println("id="+rs);
// String sr = (String)ps; error
//下面编译没问题,运行出错
//Teacher t = (Teacher)ps; //java.lang.ClassCastException: Student cannot be cast to Teacher
//判断ps真正指向的对象类型是否是Teacher类型,若是则返回true,否则返回false
if(ps instanceof Teacher){
System.out.println("可以强制类型转换");
}else{
System.out.println("不能强制类型转换");
}
if(ps instanceof Student){
System.out.println("可以强制类型转换");
}else{
System.out.println("不能强制类型转换");
}
}
}
public class Teacher extends Person{}
9.3 引用类型
9.3.1 引用类型之间的转换
基本概述
1.引用类型之间的转换必须发生在父子类之间,分为自动类型转换(向上转型)和强制类型转换(向下转型)
2.向上转换(子类类型向父类类型转换)
父类引用指向子类对象:Person p = new Student();
把一个子类对象转换为父类对象,向上转型(自动转型、隐式转型),代码中是父类引用指向子类对象,父类引用指向子类的实··
例,可以调用子类重写父类的方法以及父类派生的方法,无法调用子类独有的方法。
注意:父类中的静态方法无法被子类重写,所以向上转型之后只能调用父类原有的静态方法
3.向下转换(父类类型向子类类型转换)
子类引用指向父类实例,必须进行强制的类型转换,可以调用子类特有的类型方法,前提必须满足转型的条件才能
instanceof
运算符,可以进行判断,左边的对象是否是右边对象的实例,换句话来说,就是左侧对象是否满足右侧对象类型的特征,如果是:返回true,如果不是返回false
if(p instanceof Teacher){}
父类中的静态方法(含有static修饰的方法,只能被子类继承使用无法被子类重写)
4.当没有父子类关系发生强制转换则编译报错,当拥有父子类关系发生强制转换时编译通过
若目标类型并不是应该引用真正指向的类型是,在运行阶段发生类型转换异常
5.为了避免上述错误的发生,通常只要进行强制类型转换就需要进行判断,格式如下:
if(引用变量名 instanceof 数据类型){}
-判断指向引用的对象是否是指定的数据类型,是则返回true
9.7 深入详解final修饰符
通过final修饰以后,能够表示其修饰的类、方法和变量不可改变
9.7.1 用final修饰变量
1.用final修饰成员变量
成员变量的初始值可以在定义该变量时指定默认值。可以在构造初始化块、构造器中指定初始值,否则成员变量的初始值将是由系统自动分配的初始值。
在使用final修饰成员变量时,要么在定义成员时指定初始值,要么在初始化块和构造器中为成员变量赋初始值。
具体说明如下所示:
①修饰类属性时:可以在静态初始化块中、声明该属性时指定初始值。
②修饰实例属性时:可以在非静态初始化块、声明该属性时、构造器中指定初始值。
2.用final修饰局部变量
局部变量必须由程序员显示初始化,如果用final修饰的局部变量没有指定默认值,则后面代码可以对该局部变量赋值一次,如果指定了默认值,则后面的代码则不能对该局部变量赋值
public class chengyuan{
final int a=6;
final String str;
final int c;
final static double d;
{
str="...";
//a=9;这句话是错误的,因为a因此被赋值了
}
static //静态初始化块,可以对没有指定默认值的类属性指定初始值
{
d=5.6;
}
//构造器
public chengyuan(){
c=5;
}
public void changeFinal(){
//d=1.2;
//ch='a';
}
public static void main(String[] args){
chengyuan tf = new chengyuan();
...
}
}
9.7.2 final方法
在Java中不能重写用final修饰的方法,如果不希望子类重写父类的某个方法,则可以使用final来修饰该方法。在Java中的Obeject类中有一个final方法—getClass(),因为Java不希望任何类重写这个方法,所以使用final把这个方法密封起来。但对于该类提供的方法toString()和equals()允许子类重写,所以没有使用final修饰该方法
//下面代码试图重写final方法,执行后将会引发编译错误
public class cuowu
{
public static void test(){}
}
class Sub extends cuowu
{
//下面方法定义将出现编译错误,不能重写final方法
public void test(){}
}
在Java中,对于private方法来说,因为它仅在当前类中可见,其子类无法访问该方法。如果在子类中定义一个与父类private方法有相同方法名、相同形参列表和相同返回值类型的方法,也不是方法重写,只是重新定义了一个新方法。即使使用了final修饰了一个private访问权限的方法,仍然可以在其子类中定义与该方法具有相同方法名、相同形参列表、相同返回值类型的方法。
//例如下面的代码中,在子类中“重写”了父类的private final方法
public class chongsi{
private final void test(){}
}
class mmm extends chongsi{
//下面方法定义将不会出现问题
public void test(){}
}
final修饰的方法只是不能够被重写,并不是不能够被重载
9.8 内部类
9.8.1 何谓内部类
9.8.6 匿名内部类
匿名内部类就是没有名字的内部类
使用匿名内部类的情况
①只用到类的一个实例
②类在定义后立即用到
③类非常小(Sun推荐四行以下)
④给类命名并不会导致代码更容易被理解
在使用匿名内部类时需要遵循如下规则
匿名内部类不能有构造方法
匿名内部类不能定义任何静态成员、方法和类
匿名内部类不能是public、protected、private和static
只能创建匿名内部类的一个实例
一个匿名内部类一定是在new的后面,用其隐含实现一个接口或实现一个类
因匿名内部类为局部内部类,所以局部内部类的所有限制都对其生效
一段怪异的代码演示
//在方法中返回一个匿名内部类
public class Parcel6{
public Contents cont(){
return new Contents(){
private int i = 11;
public int value(){
return i;
};//在这里需要一个分号
}
}
public static void main(String[] args){
Parcel6 p = new Parcel6();
Content c = p.cont();
}
}
在上述代码中,方法cont()能够将下面两个动作合并在一起:返回值的生成和表示这个返回值的类的定义
更进一步的说,这个类是匿名的,它没有名字。更糟的是,看起来是我们正要创建的一个Contents对象
return new Contents()
这种奇怪的语法是指创建一个继承自Contents的匿名类的对象。通过new表达式的引用被自动向上转型为对Contents的引用。
9.8.7 匿名类和内部类中的this
有时候我们会用到一些内部类的匿名类,当在匿名类中使用this时,这个this指的是匿名类或者内部类本身。这时如果我们使用外部类的方法和变量的话,则应该加上外部类的类名。,例如下面的代码:
public class A{
int i=1;
public A(){
Thread thread = new Thread(){
public void run(){
for(;;){
A.this.run();
try{
sleep(1000);
}catch(InterruptedException ie){}
}
}
};
thread.start();
}
public void run(){
System.out.println("i="+i);
i++;
}
public static void main(String[]args)throws Exception{
new A();
}
}
在上述代码中,thread是一个匿名对象,在它的定义中,它的run函数里用到了外部类的run函数。这时由于函数同名,直接调用就不行了。这时有两种方法,一种就是把外部的run函数换一个名字,但这种办法对于一个开发中途的应用来说是不可取的。那么久可以用这个例子中的办法:用外部类名加上this引用来说明要调用的是外部类的方法run
在看看下面的代码。
this.test(new Inner(){
public void method1(){
System.out.print("1111");
}
public void method2(){
System.out.print("22222");
}
})
对于Innner类来说,除了this这个类,即代码"this.test"中的this能够调用Inner类的方法,其他地方都不行。然而这也是需要在类中有个地方保存有对这个内部类实例的引用才可以。再说明一次,内部类是用来在某个时刻调用外面的方法二存在的,这就是回调。也就是说内部类实例的方法只能在包容类的实例中调用,在其他地方无法调用。
第5章 JavaWeb
12.Ajax和JSON
Ajax
什么是Ajax
全称:Asynchrounous JavaScript And XML(异步JavaScript和XML),是指一种创建交互式网页应用的网页开发技术
Ajax技术是一组原有技术的综合应用,设计技术如下:以XMLHttpRequest为核心发送请求和接收响应,以JavaScript为基础使用XMLHttpRequest,以XML或者JSON作为数据交互的格式,以HTML和CSS作为数据展现(渲染)
Ajax交互(异步)和传统交互(同步)区别
1.请求的发送和接收
传统:浏览器直接发送HTTP请求,然后由浏览器直接接收服务器返回结果,直接呈现到浏览器的页面上
Ajax:浏览器利用js调用XMLHttpRequest对象发送HTTP请求,然后利用XMLHttpRequest接收服务器返回结果,然后还需要利用js将结果显示到浏览器页面上
2.如何区分Ajax请求和传统请求
请求的Header格式不同,Ajax请求会在请求Header部分多一组参数值x-requested-with:XMLHttpRequest
,如果存储该值则可以认为是ajax;不存在就可以认为是传统表单或者超链接
3.服务器响应结果不同
传统:服务器一般都会去调用Servlet或JSP生成一个HTML界面给浏览器,然后浏览器显示
Ajax:服务器一般都会去调用Servlet处理,然后生成一个JSON或者XML字符串结果给XMLHttpRequest
4.页面刷新不同
传统:整个页面刷新
Ajax:局部刷新
5.同步和异步不同
传统:同步交互模式,请求1—>响应1—>请求2—>响应2
Ajax:异步交互模式,请求1—>请求2—>响应1—>响应2
Ajax作用和优点
1.Ajax技术什么作用
页面局部刷新处理
页面不改变,异步请求和响应
2.Ajax技术的优点
使用户操作更加连续,提升用户体验感
Ajax交互传输数据量较小,提升程序性能
异步处理,可以进行异步加载和请求处理
减少整个页面刷新频率
Ajax使用
1.创建一个XMLHttpRequest对象,发送请求,属于客户端js编程
function sendRequest(){
//1.创建一个XMLHttpRequest对象
var xhr = null;
if(window.XMLHttpRequest){
//支持chrome,IE7 8 9
xhr = new XMLHttpRequest();
}else{//IE5,6
xhr = new ActiveXObject("Microsoft.XMLHTTP");
}
//创建一个HTTP请求
//xhr.open("get","hello.do",true);
//设置回调处理函数
/*xhr.onreadyStatechange = function(){
if(xhr.readyState == 4 && xhr.status == 200){
var msg = xhr.responseText;//获取服务器返回的字符串信息
//接下来处理回调函数返回的数值
//alet(msg);
//在页面上显示,通过id来进行选择
document.getElementById("msg").innerHTML = msg;//将刚才的标签内容回写到页面内
document.getElementById("msg").style.color="red";//可以对其样式进行设置
}
}
//发送ajax请求,请求发送后要去找对应的servlet进行处理,因此要创建一个对应的servlet
xhr.send(null);*/
}
2.服务器端处理(Servlet/JSP)
属于服务器端Java编程
public class HelloServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//service函数中的request发送一个请求,response用来响应一个请求
System.out.println("ajax请求处理");
//然后去配置一下web.xml,将该标签内配置成
//<servlet-name>HelloServlet</servlet-name>
//<url-pattern>/hello.do</url-pattern>
//然后在下方的Servers栏目右键Tomcat点击Add development,将项目挂上Tomcat,然后运行
//响应ajax,输出一个信息
response.setContentType("text/html;charset=UTF-8");
//用PrintWrite输出
PrintWriter out = response.getWriter();
Random random = new Random();
out.println("Hello World:"+random.nextInt(100));
out.close();
}
}
3.解析服务器返回数据的结果,然后显示到页面(属于客户端js编程)
//创建一个HTTP请求
xhr.open("get","hello.do",true);
//设置回调处理函数
xhr.onreadyStatechange = function(){
if(xhr.readyState == 4 && xhr.status == 200){
var msg = xhr.responseText;//获取服务器返回的字符串信息
//接下来处理回调函数返回的数值
//alet(msg);
//在页面上显示,通过id来进行选择
document.getElementById("msg").innerHTML = msg;//将刚才的标签内容回写到页面内
document.getElementById("msg").style.color="red";//可以对其样式进行设置
}
}
//发送ajax请求,请求发送后要去找对应的servlet进行处理,因此要创建一个对应的servlet
xhr.send(null);