¿Cuál es la idea más importante al aprender Java?
Por supuesto que es pensamiento orientado a objetos. Muchas de las ideas originales de POO provienen del lenguaje Simula y se han ampliado y vuelto a anotar ideas anteriores durante el proceso de mejora y estandarización del lenguaje Smalltalk. Se puede decir que el pensamiento OO y OOPL se desarrollan casi simultáneamente y se promueven entre sí. A diferencia del modelo informático real cercano a la máquina representado por la programación funcional y la programación lógica, la programación orientada a objetos apenas introduce descripciones matemáticas precisas, pero tiende a establecer un modelo de objetos que puede reflejar aproximadamente la relación entre entidades en un campo de aplicación. Es un modelo computacional que se acerca más a una visión filosófica utilizada por los humanos para reconocer cosas. Esto lleva a un tema natural, es decir, ¿qué es exactamente la programación orientada a objetos? [D&T 1988][BS 1991]. En OOP, los objetos sirven como sujetos de cálculo y tienen sus propios nombres, estados e interfaces para recibir mensajes externos. En el modelo de objetos, generar nuevos objetos, destruir objetos antiguos, enviar mensajes y responder a mensajes forman la base del modelo informático OOP.
Existen dos formas básicas de generar objetos. Una es generar nuevos objetos basados en objetos prototipo. Una es generar nuevos objetos basados en clases. El concepto de prototipo se ha utilizado en psicología cognitiva para explicar la naturaleza incremental del aprendizaje de conceptos. El modelo de prototipo en sí es un intento de generar varios objetos nuevos proporcionando un objeto representativo como base y, por lo tanto, continuar generando objetos reales más consistentes. objetos de aplicación. La delegación de prototipos también es una abstracción de objetos en programación orientada a objetos y uno de los mecanismos para compartir código. Una clase proporciona una descripción general de uno o más objetos. Desde un punto de vista formal, las clases están relacionadas con los tipos, por lo que una clase equivale a una colección de instancias derivadas de la clase. Esta visión también generará algunas contradicciones. La típica es que bajo el sistema de herencia, la compatibilidad de comportamiento entre los objetos del subconjunto (subclase) y los objetos del conjunto principal (clase principal) puede ser difícil de lograr. citado en POO que el subtipo no es igual a la subclase [Budd 2002]. En el contexto de una visión del mundo en la que todo es un objeto, nació un nuevo modelo de objetos con metaclases basado en el modelo de clases. Es decir, la clase misma también es un objeto de otras clases. Los tres puntos de vista fundamentalmente diferentes anteriores definen cada uno de ellos tres modelos de objetos basados en clases (basados en clases), basados en prototipos (basados en prototipos) y basados en metaclases (basados en metaclases). Y estos tres modelos de objetos han dado lugar a muchos lenguajes de programación diferentes (si dejamos de lado por el momento la diferencia entre estático y dinámico). Sí, C y Java con los que entramos en contacto a menudo utilizan modelos de objetos basados en clases, pero además, hay muchos OOPL con los que no hemos entrado en contacto que utilizan modelos de objetos completamente diferentes. Están utilizando otro punto de vista. Interpretar la connotación de POO.
¿Qué es un tipo?
El origen, la investigación y el desarrollo de tipos y sistemas de tipos son independientes de la programación orientada a objetos. Ya en la implementación del compilador del lenguaje FORTRAN en la década de 1950, el sistema de tipos se ha utilizado como medio de verificación de tipos. Un tipo generalizado generalmente se define como una restricción, es decir, una fórmula lógica. En el proceso de investigación de tipos, se han producido una variedad de métodos, como [Camp W 1985], etc. El enfoque algebraico es una muy buena manera de establecer especificaciones formales de tipos. Un tipo en álgebra corresponde a una secuencia de elementos sobre los cuales se definen operaciones algebraicas. Al mismo tiempo, sobre esta base, se ha utilizado el cálculo lambda de segundo orden en modelos soportados por herencia y plantillas.
En los dos métodos anteriores, se considera que el tipo es una serie de elementos que satisfacen ciertas restricciones. De una manera más abstracta, se puede considerar que un tipo especifica una restricción. Si las restricciones que especificamos son mejores, los elementos definidos correspondientes lo serán. Cuanto más preciso es el conjunto, las fórmulas lógicas se convierten en la herramienta más adecuada para describir las características tipográficas. Aquí, no queremos profundizar en los diversos modelos matemáticos de la teoría de tipos. Lo que debemos entender es que la connotación de tipo (tipo) y teoría de tipos, un concepto que se usa a menudo en los lenguajes de programación, es extremadamente rica y. sus connotaciones son extremadamente ricas. El desarrollo de su propia teoría no se limita a la programación orientada a objetos, pero cuando los dos se combinan, tiene un gran impacto en nuestra visión de la programación.
Clase, tipo e interfaz
Estos tres conceptos aparecen con mayor frecuencia en programación orientada a objetos y también son los que se confunden más fácilmente. La aclaración de estos tres conceptos es también la intención original de escribir este artículo. Primero echemos un vistazo a las descripciones de los maestros de estos tres conceptos:---
“La unidad fundamental de programación en el lenguaje de programación Java es la clase, pero la unidad fundamental del diseño orientado a objetos es el tipo. Mientras que las clases definen tipos, es muy útil y poderoso poder definir un tipo sin definir una clase. La interfaz define tipos en forma abstracta como una colección de métodos u otros tipos que forman el contrato para el tipo. ” [Jams 2000].
"En C, la clase A es un tipo definido por el usuario" [B.S 1998].
“Un tipo es un nombre usado para denotar una interfaz particular... Un objeto puede tener muchos tipos, y objetos muy diferentes pueden compartir un tipo. Parte de la interfaz de un objeto puede caracterizarse por un tipo, y otras partes por otros tipos. Dos objetos del mismo tipo sólo necesitan compartir partes de su interfaz. La interfaz puede contener otra interfaz como subconjunto. Decimos que un tipo es un subtipo de otro si su interfaz contiene la interfaz de su supertipo. A menudo hablamos de un subtipo que hereda la interfaz de su supertipo"[Gamma 1995]
En él aparecen cuatro conceptos: clase, tipo, interfaz y contrato. Los tipos de los que estamos hablando aquí son diferentes de los tipos mencionados anteriormente. Son tipos en programación orientada a objetos en un sentido estricto. Para comprender estos conceptos, primero los dividí en tres dominios conceptuales: uno es para el mundo real, otro es para un paradigma de programación específico (en este caso, el paradigma de diseño OO) y el último es para la implementación del compilador. . En otras palabras, los conceptos en el mundo real deben tener un medio para asignarse al paradigma OO, y los conceptos en el paradigma OO también deben tener la misma correspondencia conceptual en la implementación del compilador. A partir de esto, podemos decir que la clase es un concepto en el mundo real, y la OOPL tradicional proporcionará la palabra clave class para expresar soporte para la simulación del mundo real. La interfaz es un concepto correspondiente a la clase en el paradigma de programación OO. En el diseño OO, todo lo que tenemos que hacer es diseñar y programar la interfaz, y la esencia de la interfaz es un contrato entre objetos. El tipo es el concepto correspondiente definido para clases e interfaces en la implementación del compilador. Se puede decir que la clase es un concepto objetivo que existe en el mundo real y es materialista. La interfaz la define el diseñador y el concepto que existe en la mente del diseñador es idealista. El tipo es un concepto de mapeo implementado por el compilador de los dos conceptos de clase e interfaz, y también es materialista. Los tipos son principalmente predicados utilizados para guiar la verificación de tipos del compilador, las clases son plantillas para crear objetos reales y las interfaces son conceptos clave en el diseño OO. Estos tres conceptos son diferentes entre sí (están ubicados en diferentes dominios conceptuales) y están relacionados entre sí (todos representan el mapeo de diferentes dominios conceptuales del mismo concepto). Con el entendimiento anterior, echemos un vistazo a las siguientes declaraciones Java más comunes:
personas a=nuevo hombre();
¿Qué significa esto? El programador declara una variable de objeto a de tipo personas (tipo) al compilador, y la variable de objeto a en sí misma apunta a una entidad de la clase man (y el compilador entiende que la variable de objeto a apunta a una entidad de tipo entidad de man ). Volvamos a [Jams 2000], donde el significado básico de la oración se puede resumir de la siguiente manera: declarar una clase o una interfaz también registra un nuevo tipo con el compilador, y esta clase o interfaz y el tipo son *** compartir el mismo nombre. Es decir.
Todo lo que el compilador puede entender son tipos, y el trabajo del programador es transformar el concepto de clase en la realidad en el concepto de interfaz en el diseño. El compilador tiene soporte directo para los dos conceptos anteriores, es decir, se entiende una declaración de clase A o una declaración de interfaz. por el compilador como una declaración de tipo. Pero lo contrario no es necesariamente cierto. Una clase puede tener múltiples interfaces (una clase puede implementar múltiples condiciones de contrato del diseñador) y también puede tener múltiples tipos (porque un tipo es solo la implementación del concepto en el dominio de diseño de la interfaz en el compilador).
Polimorfismo, principio de sustitución, corte de objetos
El polimorfismo, como uno de los mecanismos centrales en OO, tiene ricas connotaciones. Como sugiere el nombre, polimorfismo significa un nombre con múltiples formas. Hay tres formas principales: polimorfismo de función, polimorfismo de variable de objeto y polimorfismo genérico. El polimorfismo de funciones incluye principalmente la sobrecarga y anulación de funciones. El polimorfismo genérico (genericidad) proporciona principalmente una forma de crear herramientas generales que pueden especializarse en situaciones específicas. Aquí, nos centramos en el polimorfismo de variable objeto. Antes de comprender el polimorfismo de variable objeto, primero comprendamos el principio de sustitución, uno de los mecanismos centrales de OO. Una característica de OOPL de tipo estático es que el tipo de valor contenido en una variable puede no ser igual al tipo declarado por la variable. Esta característica no está disponible en los lenguajes de programación tradicionales porque no podemos declararla como The. A la variable entera se le asigna el valor variable de la cadena. La situación en la que el principio de sustitución entra en vigor describe implícitamente la relación entre dos tipos diferentes: la herencia de tipos. Barbara Liskov describió una vez el principio de sustitución y la conexión entre los tipos en juego: Para cada objeto s de tipo S, hay un objeto t de tipo T, y para todos los programas P definidos en términos de tipo T, si el Objeto s reemplaza al objeto t, y el comportamiento del programa P permanece sin cambios, entonces el tipo S es un subtipo del tipo T [Liskov 1988]
Después de comprender el polimorfismo y el principio de sustitución, podemos continuar entendiendo la herencia en profundidad Nuevas perspectivas provocado por la combinación con el principio de sustitución. Se puede decir que la introducción de los principios de herencia y sustitución ha afectado a casi todos los OOPL, incluidos los sistemas de tipos, semántica de valores/semántica de referencia, asignación de espacio de memoria de objetos, etc. A continuación intentaré desentrañar paso a paso las distintas causas y efectos.
Primero consideren, gente a; ¿Cómo se implementará dicho código en el compilador? Es seguro que las personas del tipo estarán obligadas a oponerse a a primero, y luego se deberá asignar espacio para el objeto a. Al mismo tiempo, creamos una subclase de personas, el hombre, porque el hombre ES UN pueblo. De acuerdo con el principio de polimorfismo y sustitución, por supuesto podemos dejar que el objeto a guarde un valor de tipo man (esta es la manifestación del principio de sustitución). Esta es una descripción intuitiva, pero existen algunas dificultades en la implementación de lenguajes de programación. Sabemos que la herencia es una forma de extender interfaces e implementaciones, por lo que es difícil para nosotros asegurarnos de que el tipo man no extienda el tipo people. Una vez realizada la extensión, ¿cómo podemos usar el espacio para almacenar objetos de personas? ¿El valor del objeto tipo hombre?
personas a;
man b=new man();
a=b
Dicho código cambiará primero b El El objeto se corta y luego se almacena en un espacio de objetos. Sin embargo esto no es lo que esperábamos. Entonces, para admitir los principios de herencia, polimorfismo y reemplazo de la programación orientada a objetos, pero debemos evitar el corte de objetos, ¿qué modelo de espacio de asignación usaremos para el objeto a? Los siguientes tres métodos se utilizan comúnmente:
1. Solo se asigna el espacio de almacenamiento de las personas de la clase base para a, y no se admiten el polimorfismo de objetos ni los principios de sustitución. Este modelo tiene una asignación de memoria compacta y una alta eficiencia de almacenamiento.
2. Asigne el espacio requerido por el objeto de clase más grande en el árbol de herencia (aquí, el espacio de valores de objeto de la clase man). Este modelo es simple y puede implementar principios de polimorfismo y reemplazo para evitar el corte de objetos. problemas. , pero es muy obvio que desperdicia espacio en la memoria.
3. Asigne solo el espacio de almacenamiento necesario para guardar un puntero y asigne el espacio necesario para el tipo real del objeto a través del montón en tiempo de ejecución. Esto también puede lograr principios de polimorfismo y reemplazo y evitar el corte de objetos. problema. (Es decir, a es solo una referencia a un objeto, no un objeto real. La generación del objeto real debe ser declarada explícitamente por el programador).
Para los tres modelos de memoria mencionados anteriormente, algunos lenguajes de programación adoptan tanto el 1 como el 3. Creo que en este punto, todo el mundo debería empezar a comprender poco a poco. Sí, C, como sucesor del lenguaje C, la búsqueda de eficiencia lo obliga a adoptar el primer método mínimo de asignación de espacio estático. Dado que la eficiencia de ejecución de los programas basados en el espacio de pila es mucho mayor que la de los programas basados en el espacio de montón. Por lo tanto, C permite que el espacio de la pila se use para guardar objetos, pero también permite que el espacio del montón guarde objetos. Se puede decir que C usa un modelo de memoria mixto de 1 y 3, y los objetos en C se basan en el. 1 modelo de memoria, es decir, basado en la pila Los objetos en el espacio de memoria no pueden incorporar los principios de polimorfismo y sustitución (piense en qué objetos están basados en la pila en C), mientras que los objetos basados en el modelo de 3 memorias. admitirá el polimorfismo y el principio de sustitución (piense de nuevo en C en qué objetos están basados en montón). Aquí finalmente podemos descubrir la primera capa de misterio. Mucha gente sabe que sólo los punteros y las referencias en C pueden soportar el comportamiento polimórfico de los objetos, pero ¿por qué es así? La mejor explicación se da arriba.
El lenguaje Java es muy diferente de C debido a su concepto de diseño. Adopta el tercer modelo de objetos. Todos los objetos (excepto los objetos de tipo básico) se asignan según el montón. Es por eso que el lenguaje Java debe utilizar una máquina virtual. En C, una gran parte de los objetos no necesitan ser administrados por programadores (objetos espaciales estáticos), pero en Java, si no se utiliza el mecanismo de la máquina virtual, todos los objetos deben ser administrados por programadores y el costo de dicho desarrollo. será enorme más que realista. Esto también abre la segunda capa de confusión. Cuando comparamos los lenguajes C y Java, siempre discutimos sobre si la máquina virtual tiene su valor. Pero cuando dejas de lado la simple discusión sobre los llamados buenos y malos, y entras. Cuando se comprenda la esencia inherente del almacenamiento de objetos del lenguaje mismo, tal vez uno tenga una comprensión clara de varios sonidos propios.
Sigamos mirando hacia abajo. Los diferentes modelos de asignación de memoria de objetos afectan directamente el significado de la asignación en su lenguaje de programación. En varios lenguajes de programación, a la asignación se le pueden dar dos interpretaciones semánticas diferentes: semántica de copia y semántica de puntero. Obviamente, dado que C admite dos modelos de almacenamiento de objetos mixtos (pero el método de almacenamiento predeterminado es el almacenamiento en pila), la semántica de asignación predeterminada en C es la primera, pero C también proporciona soporte funcional para la semántica de punteros (en copia, la sobrecarga del constructor y del operador = son del usuario). -definido). Este último se utiliza en Java. Esta es la última pieza del rompecabezas que descubrimos. Los diferentes modelos de almacenamiento de objetos conducen directamente a diferentes semánticas de asignación.
Modelo informático orientado a objetos y computabilidad
La programación consiste en utilizar las instrucciones necesarias para el cálculo para formar un dispositivo informático sin importar cómo se desarrollen y mejoren nuestras ideas de programación y lenguajes de programación. , en última instancia, el modelo matemático computacional subyacente que utilizamos no ha cambiado. Pero el cambio que nos traen los lenguajes de programación de alto nivel es la construcción de un nuevo modelo de computación virtual más abstracto en su entorno de lenguaje. El modelo de computación de objetos introducido por el lenguaje Smalltalk ha cambiado fundamentalmente el modelo de computación tradicional anterior. El modelo de computación anterior resaltaba el estado de la máquina durante el proceso de cálculo secuencial, mientras que el modelo de computación de objetos actual resalta la colaboración entre objetos y se determinan sus resultados de cálculo. por El estado general de todos los objetos que participan en el cálculo. Y dado que el objeto en sí tiene su propio estado, también podemos pensar en un objeto como una pequeña máquina informática.
De esta manera, el modelo informático orientado a objetos evolucionó hacia un modelo informático cooperativo de muchas máquinas informáticas pequeñas. Como modelo informático fundamental en el campo de la informática, la máquina de Turing captura con precisión los puntos clave de la informática: qué es computable y cuánto tiempo de computación y sobrecarga de espacio de almacenamiento requiere. El modelo computacional define claramente el alcance de la computabilidad y, por lo tanto, define qué problemas son solucionables y cuáles no. La programación orientada a objetos proporciona a los programadores un nuevo modelo informático que es más abstracto y más fácil de entender, pero no supera el modelo informático matemático de la máquina de Turing representado por el sistema von Neumann. Por tanto, no podemos esperar que la programación orientada a objetos nos ayude a resolver más problemas o reducir la complejidad de las operaciones. Pero la programación orientada a objetos puede ayudarnos a describir y resolver problemas de la vida real de una manera que nos resulte más fácil de entender y aceptar.